]> Repositorios git - scryer-prolog.git/commitdiff
correct handling of floats with N digits (~f and ~Nf)
authorMarkus Triska <[email protected]>
Fri, 28 Feb 2025 07:14:34 +0000 (08:14 +0100)
committerMarkus Triska <[email protected]>
Fri, 28 Feb 2025 07:40:53 +0000 (08:40 +0100)
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

index 96266c5dfa122273fee089d32640aba1a10b5d36..63104519e18da5f015026978250ad8d47dac13a9 100644 (file)
@@ -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)  --> [].