|
259 | 259 | (values #f precision)))
|
260 | 260 |
|
261 | 261 | (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?)] |
265 | 264 | [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))])] |
277 | 272 | [digits-part
|
278 | 273 | (cond [frac-part (string-append whole-part "." frac-part)]
|
279 | 274 | [else whole-part])])
|
280 | 275 | digits-part))
|
281 | 276 |
|
| 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 | + |
282 | 301 | (define (%exponential N-abs base upper? format-exponent significand-precision exactly?)
|
283 | 302 | (define-values (N* e-adjust actual-precision)
|
284 | 303 | (scale N-abs base significand-precision exactly?))
|
|
385 | 404 | (cond [(< d 10) (integer->char (+ d (char->integer #\0)))]
|
386 | 405 | [else (integer->char (+ (- d 10) (char->integer (if upper? #\A #\a))))]))
|
387 | 406 |
|
| 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) |
388 | 410 | (define (round* x) ;; round is round-to-even :(
|
389 | 411 | (if (integer? x)
|
390 | 412 | x
|
391 |
| - (+ (truncate x) |
392 |
| - (if (even? (truncate (+ x x))) 0 1)))) |
| 413 | + (truncate (+ x 1/2)))) |
0 commit comments