From 2d4fcf9714ac0b754446761a4c60278776c36657 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Fri, 28 Feb 2025 08:14:34 +0100 Subject: [PATCH 1/2] correct handling of floats with N digits (~f and ~Nf) This addresses #2771. Many thanks to @tmerr for reporting the issue! The code was posted by @UWN in: https://github.com/mthom/scryer-prolog/discussions/2805 Many thanks! With additional inputs by @adri326 and @notoria, who also posted interesting approaches which could help to increase precision in cases that are currently not ideally handled. Thank you all! Please see the issue and discussion for more information. --- src/lib/format.pl | 45 +++++++++++++++------------------------------ 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/src/lib/format.pl b/src/lib/format.pl index 96266c5d..63104519 100644 --- a/src/lib/format.pl +++ b/src/lib/format.pl @@ -285,36 +285,12 @@ cells([~|Fs0], Args0, Tab, Es, VNs) --> cells(Fs, Args, 0, [], VNs). cells([~,s|Fs], [Arg|Args], Tab, Es, VNs) --> !, cells(Fs, Args, Tab, [chars(Arg)|Es], VNs). -cells([~,f|Fs], [Arg|Args], Tab, Es, VNs) --> !, - { G = format_number_chars(Arg, Chars) }, - cells(Fs, Args, Tab, [chars(Chars),goal(G)|Es], VNs). +cells([~,f|Fs], Args, Tab, Es, VNs) --> !, + cells([~,'6',f|Fs], Args, Tab, Es, VNs). cells([~|Fs0], Args0, Tab, Es, VNs) --> { numeric_argument(Fs0, Num, [f|Fs], Args0, [Arg|Args]) }, !, - { G = (format_number_chars(Arg, Cs0), - phrase(upto_what(Bs, .), Cs0, Cs), - ( Num =:= 0 -> Chars = Bs - ; ( Cs = ['.'|Rest] -> - length(Rest, L), - ( Num < L -> - length(Ds, Num), - append(Ds, _, Rest) - ; Num =:= L -> - Ds = Rest - ; Num > L, - Delta is Num - L, - % we should look into the float with - % greater accuracy here, and use the - % actual digits instead of 0. - length(Zs, Delta), - maplist(=('0'), Zs), - append(Rest, Zs, Ds) - ) - ; length(Ds, Num), - maplist(=('0'), Ds) - ), - append(Bs, ['.'|Ds], Chars) - )) }, + { G = phrase(float_with_n_decimal_digits(Arg, Num), Chars) }, cells(Fs, Args, Tab, [chars(Chars),goal(G)|Es], VNs). cells([~,r|Fs], Args, Tab, Es, VNs) --> !, cells([~,'8',r|Fs], Args, Tab, Es, VNs). @@ -369,9 +345,18 @@ cells(Fs0, Args, Tab, Es, VNs) --> Fs1 = [_|_] }, cells(Fs, Args, Tab, [chars(Fs1)|Es], VNs). -format_number_chars(N0, Chars) :- - N is N0, % evaluate compound expression - number_chars(N, Chars). +float_with_n_decimal_digits(F, N) --> + { Fr is abs(float_fractional_part(F)), + FrR0 is round(Fr*10^N), + I0 is truncate(F), + ( FrR0 >= 10^N + -> I is I0+truncate(sign(F)), FrR = FrR0 + ; I = I0, FrR is FrR0+10^N + ) + }, + ( { I=0, F<0, FrR>10^N } -> "-0" ; { number_chars(I, Is) }, seq(Is) ), + ".", + ( { FrR = 1 } -> "0" ; { number_chars(FrR, ['1'|FrRs]) }, seq(FrRs) ). n_newlines(N0) --> { N0 > 0, N is N0 - 1 }, [newline], n_newlines(N). n_newlines(0) --> []. From b8526e05108d7b127cb06115bcc45848695c559d Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Fri, 28 Feb 2025 08:22:54 +0100 Subject: [PATCH 2/2] FIXED: portray_clause/1 for numbers --- src/lib/format.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/format.pl b/src/lib/format.pl index 63104519..62a9e93e 100644 --- a/src/lib/format.pl +++ b/src/lib/format.pl @@ -580,6 +580,7 @@ portray_clause_(Term) --> literal(Lit, VNs) --> { write_term_to_chars(Lit, [quoted(true),variable_names(VNs),double_quotes(true)], Ls) }, ( { nonvar(Lit), + \+ number(Lit), functor(Lit, F, A), current_op(Pri, _, F), ( A =:= 0