[plt-scheme] order of magnitude

From: Jens Axel Søgaard (jensaxel at soegaard.net)
Date: Thu Nov 5 07:12:22 EST 2009

2009/11/5 Jos Koot <jos.koot at telefonica.net>:
> Some browsing did not lead me to finding a function that accepts an exact
> positive rational number and returns its order of magnitude (an exact
> integer number) Something like:
>
> (define log10 (inexact->exact (log 10)))
> (define (order-of-magnitude q) (floor (/ (inexact->exact (log q)) log10)))
>
> However, due to inexactness of function log we find:
>
> (/ (inexact->exact (log #e1000e1000000)) log10) --> close to but sligtly
> less than 1000003
>
> and hence:
>
> (order-of-magnitude #e1000e1000000) ; --> 1000002
>
> The wanted answer is 1000003. So I did the following:
>
> (define order-of-magnitude
>  (let*
>   ((log10 (inexact->exact (log 10)))
>    (10log (λ (q) (/ (inexact->exact (log q)) log10))))
>   (λ (q)
>    (unless (and (rational? q) (exact? q) (positive? q))
>     (raise-type-error 'magnitude "positive exact rational number" q))
>    (let* ((m (floor (10log q))) (k (expt 10 m)))
>     ; From now on all arithmetic operations and their operands are exact.
>     (let loop ((m m) (lower (* k 1/10)) (middle k) (upper (* k 10)))
>      (cond
>       ((<= q lower) (loop (sub1 m) (* lower 1/10) lower middle))
>       ((>= q upper) (loop (add1 m) middle upper (* upper 10)))
>       (else m)))))))
>
> (order-of-magnitude #e1000e1000000) ; --> 1000003
>
> However, this seems rather complicated. Does someone have or know of a
> simpler and faster function for this purpose?

I might be missing something, but what about this?

(define (order n)
  (inexact->exact (floor (+ 1 (/ (log n) (log 10))))))

Note: It returns the same numbers as used in:
  http://en.wikipedia.org/wiki/Order_of_magnitude
so it gives slightly different results than your
function.

-- 
Jens Axel Søgaard


Posted on the users mailing list.