[racket] Decimal rounding problem
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 ⊥