Skip to content

Commit 35879eb

Browse files
committed
fix rounding in ~r, docs
Merge to 5.3.2. (cherry picked from commit 1109e0f)
1 parent 665d627 commit 35879eb

File tree

3 files changed

+58
-19
lines changed

3 files changed

+58
-19
lines changed

collects/racket/format.rkt

+37-16
Original file line numberDiff line numberDiff line change
@@ -259,26 +259,45 @@
259259
(values #f precision)))
260260

261261
(define (%positional N-abs base upper? precision exactly?)
262-
(let* ([Nw (inexact->exact (floor N-abs))]
263-
[Nf (- N-abs Nw)]
264-
[whole-part (number->string* Nw base upper?)]
262+
(define-values (Nw Nf) (decompose-positional N-abs base precision))
263+
(let* ([whole-part (number->string* Nw base upper?)]
265264
[frac-part
266-
(let* ([Nf* (inexact->exact (round (* Nf (expt base precision))))])
267-
(cond [(and exactly? (= precision 0)) ""]
268-
[exactly? (number->fraction-string Nf* base upper? precision)]
269-
[(= Nf* 0) #f]
270-
[else
271-
(let-values ([(needed-precision Nf**)
272-
(let loop ([np precision] [Nf* Nf*])
273-
(let-values ([(q r) (quotient/remainder Nf* base)])
274-
(cond [(zero? r) (loop (sub1 np) q)]
275-
[else (values np Nf*)])))])
276-
(number->fraction-string Nf** base upper? needed-precision))]))]
265+
(cond [(and exactly? (= precision 0)) ""]
266+
[exactly? (number->fraction-string Nf base upper? precision)]
267+
[(= Nf 0) #f]
268+
[else
269+
(let-values ([(needed-precision Nf*)
270+
(reduce-precision base precision Nf)])
271+
(number->fraction-string Nf* base upper? needed-precision))])]
277272
[digits-part
278273
(cond [frac-part (string-append whole-part "." frac-part)]
279274
[else whole-part])])
280275
digits-part))
281276

277+
;; decompose-positional : nonnegative-real positive-nat nat -> (values nat nat)
278+
;; Returns (values whole fraction) where
279+
;; N-abs is approximately (+ whole (/ fraction (expt base precision)))
280+
(define (decompose-positional N-abs base precision)
281+
(let* ([Nw (inexact->exact (floor N-abs))]
282+
[Nf (- N-abs Nw)]
283+
[base^prec (expt base precision)]
284+
[Nf* (inexact->exact (round* (* Nf base^prec)))])
285+
(cond [(< Nf* base^prec)
286+
(values Nw Nf*)]
287+
[else
288+
(values (add1 Nw) 0)])))
289+
290+
;; reduce-precision : nat nat nat -> (values nat nat)
291+
;; Returns (values needed-precision N*) where
292+
;; (/ N (expt base precision)) = (/ N* (expt base needed-precision))
293+
(define (reduce-precision base precision N)
294+
(if (zero? N)
295+
(values 0 0)
296+
(let loop ([np precision] [N* N])
297+
(let-values ([(q r) (quotient/remainder N* base)])
298+
(cond [(zero? r) (loop (sub1 np) q)]
299+
[else (values np N*)])))))
300+
282301
(define (%exponential N-abs base upper? format-exponent significand-precision exactly?)
283302
(define-values (N* e-adjust actual-precision)
284303
(scale N-abs base significand-precision exactly?))
@@ -385,8 +404,10 @@
385404
(cond [(< d 10) (integer->char (+ d (char->integer #\0)))]
386405
[else (integer->char (+ (- d 10) (char->integer (if upper? #\A #\a))))]))
387406

407+
;; round* : nonnegative-real -> nonnegative-integer (preserving exactness)
408+
;; Implements "round half up" rounding (thus this library formats using
409+
;; "round half away from zero", since it applies round* to absolute values)
388410
(define (round* x) ;; round is round-to-even :(
389411
(if (integer? x)
390412
x
391-
(+ (truncate x)
392-
(if (even? (truncate (+ x x))) 0 1))))
413+
(truncate (+ x 1/2))))

collects/scribblings/reference/format.scrbl

+1-1
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ marker is @racket["..."].
215215
[#:precision precision
216216
(or/c exact-nonnegative-integer?
217217
(list/c '= exact-nonnegative-integer?))
218-
3]
218+
6]
219219
[#:notation notation
220220
(or/c 'positional 'exponential
221221
(-> rational? (or/c 'positional 'exponential)))

collects/tests/racket/format.rkt

+20-2
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,24 @@
270270
"D.EADBEF×16^+07")
271271

272272
(tc (~r 33.99508664763296 #:precision 1 #:min-width 5)
273-
" 33.1")
273+
" 34")
274274
(tc (~r 33.99508664763296 #:precision 2 #:min-width 7)
275-
" 33.1")
275+
" 34")
276+
277+
(tc (~r 33.99508664763296 #:precision 1)
278+
"34")
279+
(tc (~r 33.99508664763296 #:precision '(= 1))
280+
"34.0")
281+
(tc (~r 33.99508664763296 #:precision '(= 2))
282+
"34.00")
283+
(tc (~r 33.99508664763296 #:precision '(= 3))
284+
"33.995")
285+
286+
(tc (~r -33.99508664763296 #:precision 1)
287+
"-34")
288+
(tc (~r -33.99508664763296 #:precision '(= 1))
289+
"-34.0")
290+
(tc (~r -33.99508664763296 #:precision '(= 2))
291+
"-34.00")
292+
(tc (~r -33.99508664763296 #:precision '(= 3))
293+
"-33.995")

0 commit comments

Comments
 (0)