Menu

#419 float format directive ~ve prints spurious digits

closed-fixed
clisp (524)
5
2014-08-18
2007-09-08
No

Observed in Clisp 2.39 on Linux:

[1]> (format t "~ve~%" 21 46d7)
=> 4.5999999999999996d+8

Note that 46d7 is an integer which can be represented exactly as a double float.

Discussion

  • Raymond Toy

    Raymond Toy - 2008-03-28

    Logged In: YES
    user_id=28849
    Originator: NO

    I think this is caused by format-scale-exponent. I think it divides 46d7 by 1d8 (or 1d9?) That causes a round-off error which shows up in the printed answer.

    The only solution I know of is not to do that scaling and to use a different printing algorithm.

     
  • Sam Steingold

    Sam Steingold - 2008-03-28

    Logged In: YES
    user_id=5735
    Originator: NO

    increasing precision can result in
    > (> (format nil "~ve" 26 46d7)
    " 4.5999999999999999998d+8"
    > (= 4.5999999999999999998d+8 46d7)
    T

    which is no longer a bug technically but still worse than sbcl's
    " 4.6d+8"
    do you know what they do?

     
  • Raymond Toy

    Raymond Toy - 2008-03-28

    Logged In: YES
    user_id=28849
    Originator: NO

    Cmucl and sbcl both use Burger and Dybvig's printing algorithm for the core printing routine. But that's not enough. AFAIK, you need to get rid of the scaling part altogether. CMUCL does that. Don't know about sbcl.

    There are lots of hairy little corners to handle.

     
  • Sam Steingold

    Sam Steingold - 2008-03-28

    Logged In: YES
    user_id=5735
    Originator: NO

    the following patch appears to fix the problem:
    --- format.lisp.~1.48.~ 2006-12-27 18:01:58.000000000 -0500
    +++ format.lisp 2008-03-28 17:31:36.002851000 -0400
    @@ -712,7 +712,7 @@
    (declare (ignore significand))
    (if (zerop arg)
    (values zero 0)
    - (let* ((expon10a (truncate (* expon lg2))) ; round is not used, in order to avoid overflow
    + (let* ((expon10a (round (* expon lg2)))
    (signif10a (/ arg (expt ten expon10a))))
    (do ((ten-power ten (* ten-power ten))
    (signif10b signif10a (/ signif10a ten-power))

    it breaks printing large numbers though, e.g.,
    > (format nil "~ve" 31 most-positive-short-float)
    *** - /: floating point overflow
    which should be fixed by rewriting is in C and increasing the precision.
    are there any other pitfalls here?

     
  • Raymond Toy

    Raymond Toy - 2008-03-29

    Logged In: YES
    user_id=28849
    Originator: NO

    As far as I can tell, format-scale-exponent-aux still returns arg/10^n. There will be a round off error such that arg/10^n won't have the same digits as arg in some cases. The only way I could think of to solve this was to compute n, but don't do the division. Then the main print routine prints arg correctly with just the desired digits, but no exponent. Since you know the exponent n already, you can just print that out.

     
  • Sam Steingold

    Sam Steingold - 2008-04-03

    Logged In: YES
    user_id=5735
    Originator: NO

    * lisparit.d (FLOAT-SCALE-EXPONENT): implement
    * constsym.d, subr.f (float_scale_exponent): declare
    * format.lisp (format-scale-exponent-aux, format-scale-exponent): remove
    (format-float-for-e, format-general-float): use
    FLOAT-SCALE-EXPONENT instead of FORMAT-SCALE-EXPONENT

     
  • Sam Steingold

    Sam Steingold - 2008-04-03
    • assigned_to: haible --> sds
    • status: open --> closed-fixed
     
  • Sam Steingold

    Sam Steingold - 2008-04-03

    Logged In: YES
    user_id=5735
    Originator: NO

    thank you for your bug report.
    the bug has been fixed in the CVS tree.
    you can either wait for the next release (recommended)
    or check out the current CVS tree (see http://clisp.cons.org\)
    and build CLISP from the sources (be advised that between
    releases the CVS tree is very unstable and may not even build
    on your platform).

     

Log in to post a comment.