Big Numbers: Testing

June 21, 2011

The current version of the big number library is shown on the next page. It includes a few functions we haven’t seen before: big?, which tests if an object is in the proper form to be considered a big number, big-sign which consolidates the tests for positive, negative and zero, big-quotient and big-remainder, for when you need one or the other but not both, and big-modulo. Also, the code has been refactored so that common subroutines appear only once, and (very) brief documentation is provided.

Our test consists of a long list of edge conditions followed by a thousand randomly-generated tests of arithmetic; the arithmetic tests use division, which tests all the other functions:

(define (test-big) ; no news is good news
  (let ((zero '(0)) (one '(1 1)) (minus-one '(-1 1))
        (base '(2 0 1)) (minus-base '(-2 0 1))
        (b1 (string->big "737")) (b2 (string->big "13290059"))
        (ten25 (string->big "10000000000000000000000000"))
        (ten24 (string->big "1000000000000000000000000")))
    (assert (string->big "0") zero)
    (assert (big->string (string->big "0")) "0")
    (assert (big->string (string->big "1")) "1")
    (assert (big->string (string->big "2")) "2")
    (assert (big->string (string->big "-1")) "-1")
    (assert (big->string (string->big "42")) "42")
    (assert (big->string (string->big "-42")) "-42")
    (assert (big->string (string->big "737")) "737")
    (assert (big->string (string->big "13290059")) "13290059")
    (assert (big-abs one) one)
    (assert (big-abs minus-one) one)
    (assert (big-negate one) minus-one)
    (assert (big-negate minus-one) one)
    (assert (big-negate base) minus-base)
    (assert (big->string (big-negate b1)) "-737")
    (assert (big->string (big-negate b2)) "-13290059")
    (assert (big-zero? zero) #t)
    (assert (big-zero? b2) #f)
    (assert (big-zero? minus-one) #f)
    (assert (big-positive? zero) #f)
    (assert (big-positive? b2) #t)
    (assert (big-positive? minus-one) #f)
    (assert (big-negative? zero) #f)
    (assert (big-negative? b2) #f)
    (assert (big-negative? minus-one) #t)
    (assert (big-even? zero) #t)
    (assert (big-odd? zero) #f)
    (assert (big-even? b2) #f)
    (assert (big-odd? b2) #t)
    (assert (big-even? minus-base) #t)
    (assert (big-odd? minus-base) #f)
    (assert (big-lt? b1 b2) #t)
    (assert (big-lt? b1 (big-negate b2)) #f)
    (assert (big-le? b1 b1) #t)
    (assert (big-le? b2 b1) #f)
    (assert (big-lt? zero one) #t)
    (assert (big-le? zero one) #t)
    (assert (big-lt? b1 b1) #f)
    (assert (big-eq? b1 b1) #t)
    (assert (big-eq? b1 b2) #f)
    (assert (big-ne? b1 b2) #t)
    (assert (big-ne? b1 b1) #f)
    (assert (big-gt? b1 b2) #f)
    (assert (big-gt? b1 (big-negate b2)) #t)
    (assert (big-ge? b1 b1) #t)
    (assert (big-ge? b2 b1) #t)
    (assert (big-gt? zero one) #f)
    (assert (big-ge? zero one) #f)
    (assert (big-gt? b1 b1) #f)
    (do ((i 0 (+ i 1))
         (n (next ten25) (next ten25))
         (d (next ten24) (next ten24)))
        ((= i 1000))
      (call-with-values
        (lambda () (big-divide n d))
        (lambda (q r)
          (if (big-negative? n)
              (begin (assert (big-le? r '(0)) #t)
                     (assert (big-lt? (big-negate (big-abs d)) r) #t))
              (begin (assert (big-ge? r '(0)) #t)
                     (assert (big-lt? r (big-abs d)) #t)))
          (assert (big-minus (big-times q d) (big-negate r)) n))))))

Random numbers are provided by a Park-Miller random number generator; it is built specifically for the test and should not be used otherwise:

(define next ; park-miller generator, suitable only for testing
  (let ((a (string->big "16807"))
        (m (string->big "2147483647"))
        (seed (string->big "1043618065")))
    (lambda (n)
      (let* ((minus-n (big-negate n))
             (span (big-plus (big-times n '(1 2)) '(1 1))))
        (set! seed (big-modulo (big-times a seed) m))
        (big-plus minus-n (big-quotient (big-times seed span) m))))))

To call the test, say (test-big); if it produces no output, all is well. The only bug that testing revealed was in the string->big function, which returned (1 0) instead of (0) when given the string "0"; once found, the bug was easy to fix. You can run the program at http://programmingpraxis.codepad.org/um9s9k8r.

Pages: 1 2 3

Leave a comment