[racket] Decimal rounding problem

From: Ryan Culpepper (ryan at cs.utah.edu)
Date: Thu Nov 29 12:21:53 EST 2012

On 11/29/2012 11:06 AM, Stephen Bloch wrote:
>
> On Nov 29, 2012, at 9:44 AM, Greg Graham wrote:
>
>> I am trying to report GPA calculation results to 2 decimal places, so I thought real->decimal-string would do the trick. However, the following behavior surprised me:
>>
>>> (real->decimal-string 3.225 2)
>> "3.23"
>>> (real->decimal-string 4.225 2)
>> "4.22"
>>
>> I would like the second answer to be "4.23", which is what a student would expect to see if they did the calculations themselves. The documentation for real->decimal-string says that it first converts the argument to an exact number. I suspect the problem has something to do with this:
>>
>>> (inexact->exact 4.225)
>> 4 126663739519795/562949953421312
>>> (/ 126663739519795.0 562949953421312.0)
>> 0.22499999999999964
>>
>> Is there another rounding function that would just round the floating point without going through the conversion to exact?
>
> Another rounding function won't help, because by the time the READER has finished with the character string "4.225", the internal form is already slightly less than 4225/1000.  And if you're getting the inexact 4.225 from somewhere else, again it's not really 4225/1000 so it's already too late to round it the way you want.
>
> You could work in a student language, where the reader reads decimals as exact by default :-)
>
> Seriously, I'm sure there's a way to tell the reader in other languages to read decimals as exact; I just don't know what it is.

Prefix the number with "#e", as in

   > #e4.225
   169/40

As an alternative, you could create a language that sets the 
'read-decimal-as-inexact' reader parameter to #f before reading the 
module contents. Try saving the following as s-exp-exact/lang/reader.rkt 
(adapted from s-exp/lang/reader.rkt with some help from Carl):

   (module reader syntax/module-reader
     #:language (lambda (p) (read-syntax (object-name p) p))
     #:wrapper1 (lambda (go)
                  (parameterize ((read-decimal-as-inexact #f)) (go))))

Then run

   #lang s-exp-exact racket
   (exact? 4.225)

Ryan


Posted on the users mailing list.