; logarithm tables

(define (range . args)
  (case (length args)
    ((1) (range 0 (car args) (if (negative? (car args)) -1 1)))
    ((2) (range (car args) (cadr args) (if (< (car args) (cadr args)) 1 -1)))
    ((3) (let ((le? (if (negative? (caddr args)) >= <=)))
           (let loop ((x(car args)) (xs '()))
             (if (le? (cadr args) x)
                 (reverse xs)
                 (loop (+ x (caddr args)) (cons x xs))))))
    (else (error 'range "unrecognized arguments"))))

(define (pr4 x)
  (let* ((x (inexact->exact (round (* x 10000))))
         (s (number->string x)))
    (if (< x 1000) (set! s (string-append "0" s)))
    (if (< x 100) (set! s (string-append "0" s)))
    (if (< x 10) (set! s (string-append "0" s)))
    s))

(define (pr2 x)
  (let ((s (number->string x)))
    (if (< x 10) (set! s (string-append " " s)))
    s))

(define (log10 x) (/ (log x) (log 10)))

(define (average xs) (/ (apply + xs) (length xs)))

(define (display-header)
  (display "   ")
  (do ((j 0 (+ j 1))) ((= j 10))
    (display "    ")
    (display j))
  (display " ")
  (do ((j 1 (+ j 1))) ((= j 10))
    (display "  ")
    (display j))
  (newline))

(define (display-bar)
  (display "-- ")
  (do ((j 0 (+ j 1))) ((= j 10))
    (display " ") (display "----"))
  (display " ")
  (do ((j 1 (+ j 1))) ((= j 10))
    (display " ") (display "--"))
  (newline))

(define (log-average-interp i k)
  (define (add-on j)
    (- (* (log10 (/ (+ i (* j 10) k) 1000.0)) 10000)
       (* (log10 (/ (+ i (* j 10)) 1000.0)) 10000)))
  (inexact->exact (round (average (map add-on (range 10))))))

(define (log-display-interp i)
  (display " ")
  (do ((k 1 (+ k 1))) ((= 10 k))
    (display " ")
    (display (pr2 (log-average-interp i k)))))

(define (log-display-line i)
    (do ((j 0 (+ j 10))) ((= 100 j))
      (display " ")
      (display (pr4 (log10 (/ (+ i j) 1000)))))
    (log-display-interp i))

(define (log-display-table)
  (display-header)
  (do ((i 1000 (+ i 100))) ((= 10000 i))
    (if (zero? (modulo i 1000)) (display-bar))
    (display (/ i 100))
    (display " ")
    (log-display-line i)
    (newline)))

(define (alog-average-interp i k)
  (define (add-on j)
    (- (* (expt 10 (+ 1 (/ (+ i (* j 10) k) 10000))) 100)
       (* (expt 10 (+ 1 (/ (+ i (* j 10)) 10000))) 100)))
  (inexact->exact (round (average (map add-on (range 10))))))

(define (alog-display-interp i)
  (display " ")
  (do ((k 1 (+ k 1))) ((= 10 k))
    (display " ")
    (display (pr2 (alog-average-interp i k)))))

(define (alog-display-line i)
  (do ((j 0 (+ j 10))) ((= 100 j))
    (display " ")
    (display (pr4 (/ (expt 10 (+ 1 (/ (+ i j) 10000))) 100))))
  (alog-display-interp i))

(define (alog-display-table)
  (display-header)
  (do ((i 1000 (+ i 100))) ((= 10000 i))
    (if (zero? (modulo i 1000)) (display-bar))
    (display (/ i 100))
    (display " ")
    (alog-display-line i)
    (newline)))

(display "Logarithms") (newline) (newline)
(log-display-table) (newline) (newline) (newline)
(display "Anti-Logarithms") (newline) (newline)
(alog-display-table)
