mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-11 11:53:51 +00:00
185 lines
5.0 KiB
Mathematica
185 lines
5.0 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ts=4 sw=4 et ft=mercury
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module fib_string.
|
|
|
|
:- interface.
|
|
|
|
:- import_module io.
|
|
|
|
:- pred main(io::di, io::uo) is cc_multi.
|
|
|
|
:- implementation.
|
|
|
|
:- import_module assoc_list.
|
|
:- import_module benchmarking.
|
|
:- import_module int.
|
|
:- import_module list.
|
|
:- import_module pair.
|
|
:- import_module require.
|
|
:- import_module solutions.
|
|
:- import_module string.
|
|
|
|
:- pragma require_feature_set([memo]).
|
|
|
|
main(!IO) :-
|
|
perform_trials("oneone", !IO).
|
|
|
|
:- pred perform_trials(string::in, io::di, io::uo) is cc_multi.
|
|
|
|
perform_trials(N, !IO) :-
|
|
trial(N, Time, MTime),
|
|
% io.write_string(N, !IO),
|
|
% io.write_string(": ", !IO),
|
|
% io.write_int(Time, !IO),
|
|
% io.write_string("ms vs ", !IO),
|
|
% io.write_int(MTime, !IO),
|
|
% io.write_string("ms\n", !IO),
|
|
( if
|
|
(
|
|
Time > 10 * MTime,
|
|
MTime > 0 % untabled takes ten times as long
|
|
;
|
|
Time > 100, % untabled takes at least 100 ms
|
|
MTime < 1 % while tabled takes at most 1 ms
|
|
)
|
|
then
|
|
io.write_string("tabling works\n", !IO)
|
|
else if
|
|
Time > 10000 % untabled takes at least 10 seconds
|
|
then
|
|
io.write_string("tabling does not appear to work\n", !IO)
|
|
else
|
|
% We couldn't get a measurable result with N,
|
|
% and it looks like we can afford a bigger trial
|
|
perform_trials(add_strings(N, "three"), !IO)
|
|
).
|
|
|
|
:- pred trial(string::in, int::out, int::out) is cc_multi.
|
|
|
|
trial(N, Time, MTime) :-
|
|
benchmark_det(fib, N, Res, 1, Time),
|
|
benchmark_det(mfib, N, MRes, 1, MTime),
|
|
require(unify(Res, MRes), "tabling produces wrong answer").
|
|
|
|
:- pred fib(string::in, string::out) is det.
|
|
|
|
fib(N, F) :-
|
|
( if string_to_num(N) < 2 then
|
|
F = num_to_string(1)
|
|
else
|
|
One = num_to_string(1),
|
|
Two = num_to_string(2),
|
|
fib(subtract_strings(N, One), F1),
|
|
fib(subtract_strings(N, Two), F2),
|
|
F = add_strings(F1, F2)
|
|
).
|
|
|
|
:- pred mfib(string::in, string::out) is det.
|
|
:- pragma memo(mfib/2).
|
|
|
|
mfib(N, F) :-
|
|
( if string_to_num(N) < 2 then
|
|
F = num_to_string(1)
|
|
else
|
|
One = num_to_string(1),
|
|
Two = num_to_string(2),
|
|
mfib(subtract_strings(N, One), F1),
|
|
mfib(subtract_strings(N, Two), F2),
|
|
F = add_strings(F1, F2)
|
|
).
|
|
|
|
:- func add_strings(string, string) = string.
|
|
|
|
add_strings(S1, S2) =
|
|
num_to_string(string_to_num(S1) + string_to_num(S2)).
|
|
|
|
:- func subtract_strings(string, string) = string.
|
|
|
|
subtract_strings(S1, S2) =
|
|
num_to_string(string_to_num(S1) - string_to_num(S2)).
|
|
|
|
:- func string_to_num(string) = int.
|
|
|
|
string_to_num(String) = Num :-
|
|
translate_last_digit(String, LastNum, RestString),
|
|
( if RestString = "" then
|
|
Num = LastNum
|
|
else
|
|
Num = string_to_num(RestString) * 10 + LastNum
|
|
).
|
|
|
|
:- pred translate_last_digit(string::in, int::out, string::out) is det.
|
|
|
|
translate_last_digit(String, LastDigit, Rest) :-
|
|
digits(Pairs),
|
|
translate_last_digit_2(Pairs, String, LastDigit, Rest).
|
|
|
|
:- pred translate_last_digit_2(assoc_list(string, int)::in, string::in,
|
|
int::out, string::out) is det.
|
|
|
|
translate_last_digit_2([], _, _, _) :-
|
|
error("cannot determine last digit").
|
|
translate_last_digit_2([DigitStr - DigitNum | Digits], String, Last, Rest) :-
|
|
( if string.remove_suffix(String, DigitStr, RestPrime) then
|
|
Last = DigitNum,
|
|
Rest = RestPrime
|
|
else
|
|
translate_last_digit_2(Digits, String, Last, Rest)
|
|
).
|
|
|
|
:- func num_to_string(int) = string.
|
|
|
|
num_to_string(Int) = String :-
|
|
translate_digits(Int, Digits),
|
|
string.append_list(Digits, String).
|
|
|
|
:- pred translate_digits(int::in, list(string)::out) is det.
|
|
|
|
translate_digits(N, Digits) :-
|
|
( if N < 10 then
|
|
translate_digit(N, Digit),
|
|
Digits = [Digit]
|
|
else
|
|
Last = N mod 10,
|
|
Rest = N // 10,
|
|
translate_digit(Last, LastDigit),
|
|
translate_digits(Rest, RestDigits),
|
|
list.append(RestDigits, [LastDigit], Digits)
|
|
).
|
|
|
|
:- pred translate_digit(int::in, string::out) is det.
|
|
|
|
translate_digit(Int, String) :-
|
|
( if translate_digit_2(Int, StringPrime) then
|
|
String = StringPrime
|
|
else
|
|
error("translate_digit give non-digit")
|
|
).
|
|
|
|
:- pred translate_digit_2(int, string).
|
|
:- mode translate_digit_2(in, out) is semidet.
|
|
:- mode translate_digit_2(out, out) is multi.
|
|
|
|
translate_digit_2(0, "zero").
|
|
translate_digit_2(1, "one").
|
|
translate_digit_2(2, "two").
|
|
translate_digit_2(3, "three").
|
|
translate_digit_2(4, "four").
|
|
translate_digit_2(5, "five").
|
|
translate_digit_2(6, "six").
|
|
translate_digit_2(7, "seven").
|
|
translate_digit_2(8, "eight").
|
|
translate_digit_2(9, "nine").
|
|
|
|
:- pred digits(assoc_list(string, int)::out) is det.
|
|
:- pragma memo(digits/1).
|
|
|
|
digits(PairList) :-
|
|
solutions(
|
|
( pred(Pair::out) is multi :-
|
|
translate_digit_2(Int, String),
|
|
Pair = String - Int
|
|
), PairList).
|