[racket] Decimal rounding problem

From: Neil Toronto (neil.toronto at gmail.com)
Date: Thu Nov 29 10:53:54 EST 2012

On 11/29/2012 07:55 AM, Matthew Flatt wrote:
> At Thu, 29 Nov 2012 14:44:38 +0000, Greg Graham wrote:
> There are a couple of issues here.
>
> First, the inexact number 4.225 is actually slightly smaller than the
> exact value 4.225:
>
>[...]
>
> Even if you use the exact number 4.225, though, you get a "2" as the
> last digit:
>
>   > (real->decimal-string #e4.225 2)
>   "4.22"
>
> That's because rounding in Racket is to "even" --- a different
> convention than the one taught to most students, but one that it often
> preferred in computing (because it often reduces accumulated error, as I
> understand it).

Right. If you want to implement rounding with ties rounded away from 
zero, you've got to do it yourself. Here's an implementation, which 
takes an optional `scale' argument:

(define (round/ties-away x [scale 1])
   (cond [(not (= scale 1))  (/ (round/ties-away (* x scale) 1) scale)]
         [(x . < . 0)  (truncate (- x 1/2))]
         [else         (truncate (+ x 1/2))]))

 > (real->decimal-string (round/ties-away #e4.225 100) 2)
"4.23"

You'd still need to compute using exact numbers, though, because as 
Matthew said, 4.225 is a little smaller than #e4.225:

 > (real->decimal-string (round/ties-away 4.225 100) 2)
"4.22"

Also, multiplying and dividing inexact numbers by non-powers-of-two 
introduces a little bit of error, which can make scaling before rounding 
produce the wrong result. With exact numbers, though, it's, uh, exact.

Neil ⊥


Posted on the users mailing list.