From 6e5cf18539ee98bf2e5d05f7e6513e79a9aca1f7 Mon Sep 17 00:00:00 2001 From: Rose Hogenson Date: Sun, 7 Aug 2022 15:52:39 -0700 Subject: Add numbers. --- lib/scheme/base/80-number.csc | 821 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 821 insertions(+) create mode 100644 lib/scheme/base/80-number.csc (limited to 'lib/scheme/base') diff --git a/lib/scheme/base/80-number.csc b/lib/scheme/base/80-number.csc new file mode 100644 index 0000000..20f8db8 --- /dev/null +++ b/lib/scheme/base/80-number.csc @@ -0,0 +1,821 @@ +(export + * + + + - + / + < + <= + = + > + >= + abs + ceiling + denominator + even? + exact-integer-sqrt + expt + floor + floor-quotient + floor-remainder + floor/ + gcd + integer? + lcm + max + min + modulo + negative? + number? + numerator + odd? + positive? + quotient + rational? + remainder + round + square + truncate + truncate-quotient + truncate-remainder + truncate/ + zero?) +(import (only (csc builtins) + call-builtin)) +(begin + + + ;; Integers + + + (define-record-type + (make-boxed-int positive? digits) + boxed-int? + (positive? boxed-int-positive?) + (digits boxed-int-digits)) + + + (define (small-int? obj) + (call-builtin eq? 1 (call-builtin typeof obj))) + + + (define (integer? obj) + (or (small-int? obj) + (boxed-int? obj))) + + + (define (int=? n1 n2) + (cond + ((and (small-int? n1) (small-int? n2)) + (call-builtin eq? n1 n2)) + ((and (boxed-int? n1) (boxed-int? n2)) + (let ((n1-digits (boxed-int-digits n1)) + (n2-digits (boxed-int-digits n2))) + (and (boolean=? (boxed-int-positive? n1) (boxed-int-positive? n2)) + (call-builtin eq? (vector-length n1-digits) (vector-length n2-digits)) + (let loop ((i 0)) + (if (call-builtin int n2 + + + (define (int>? n1 n2) + (int=? n1 n2) + (or (int=? n1 n2) + (int>? n1 n2))) + + + (define (zero? obj) + (call-builtin eq? 0 obj)) + + + (define (odd? n) + (cond + ((small-int? n) + (int=? 1 (call-builtin mod n 2))) + (else + (odd? (vector-ref (boxed-int-digits n) 0))))) + + + (define (even? n) + (cond + ((small-int? n) + (int=? 0 (call-builtin mod n 2))) + (else + (even? (vector-ref (boxed-int-digits n) 0))))) + + + (define small-int-max #x3FFFFFFFFFFFFFFF) ; 2^62 - 1 + + + (define small-int-min (- #x4000000000000000)) ; -(2^62) + + + (define digit-mask #x2000000000000000) ; 2^61. Digits are 61-bit unsigned numbers. + + + (define (split-carry-bit n) + (values + (call-builtin div n digit-mask) + (call-builtin mod n digit-mask))) + + + (define (denormalized-int n) + (define-values (sgn n*) (if (int-positive? n) + (values #t n) + (values #f (- n)))) + (define-values (n2 n1) (split-carry-bit n*)) + (if (zero? n2) + (make-boxed-int sgn (vector n1)) + (make-boxed-int sgn (vector n1 n2)))) + + + (define (big-int+ n1 n2) + (cond + ((and (boxed-int-positive? n1) (boxed-int-negative? n2)) + (big-int- n1 (- n2))) + ((and (boxed-int-negative? n1) (boxed-int-positive? n2)) + (big-int- n2 (- n1))) + ((and (boxed-int-negative? n1) (boxed-int-negative? n2)) + (- (big-int+ (- n1) (- n2)))) + (else + (let* ((n1-digits (boxed-int-digits n1)) + (n2-digits (boxed-int-digits n2)) + (n1-ndigits (vector-length n1-digits)) + (n2-ndigits (vector-length n2-digits)) + (out-digits (make-vector (max n1-ndigits + n2-ndigits)))) + (let loop ((i 0) + (carry 0)) + (cond + ((and (int=? i 0) + (zero? (vector-ref digits i))) + (loop (int- i 1) (int+ 1 n)) + n))) + (make-boxed-int (boxed-int-positive? n) (vector-copy digits 0 (int- (vector-length digits) leading-zeros)))) + + + (define (normalize n) + (define digits (boxed-int-digits n)) + (if (and (int + (make-quotient numerator denominator) + quotient? + (numerator quotient-numerator) + (denominator quotient-denominator)) + + + (define (rational? obj) + (or (integer? obj) + (quotient? obj))) + + + (define number? rational?) ; only rational numbers for now. + + + (define (numerator q) + (cond + ((integer? q) q) + (else (quotient-numerator q)))) + + + (define (denominator q) + (cond + ((integer? q) 1) + (else (quotient-denominator q)))) + + + (define (= z1 z2 . zs) + (cond + ((integer? z1) + (let loop ((zs (cons z2 zs))) + (or (null? zs) + (and (int=? z1 (car zs)) + (loop (cdr zs)))))) + (else + (let ((n (numerator z1)) + (d (denominator z1))) + (let loop ((zs (cons z2 zs))) + (or (null? zs) + (and (int=? n (numerator (car zs))) + (int=? d (denominator (car zs))) + (loop (cdr zs))))))))) + + + (define (<2 x1 x2) + (if (and (integer? x1) (integer? x2)) + (int x1 x2 . xs) + (let loop ((x1 x1) + (xs (cons x2 xs))) + (or (null? xs) + (and (<2 (car xs) x1) + (loop (car xs) + (cdr xs)))))) + + + (define (<= x1 x2 . xs) + (let loop ((x1 x1) + (xs (cons x2 xs))) + (or (null? xs) + (and (or (= x1 (car xs)) + (< x1 (car xs))) + (loop (car xs) (cdr xs)))))) + + + (define (>= x1 x2 . xs) + (let loop ((x1 x1) + (xs (cons x2 xs))) + (or (null? xs) + (and (or (= x1 (car xs)) + (> x1 (car xs))) + (loop (car xs) (cdr xs)))))) + + + (define (positive? x) + (> x 0)) + + + (define (negative? x) + (< x 0)) + + + (define (max x1 . xs) + (let loop ((xs xs) + (m x1)) + (if (null? xs) + m + (loop (cdr xs) + (if (> (car xs) m) + (car xs) + m))))) + + + (define (min x1 . xs) + (let loop ((xs xs) + (m m1)) + (if (null? xs) + m + (loop (cdr xs) + (if (< (car xs) m) + (car xs) + m))))) + + + (define + + (case-lambda + ((x1 x2) + (cond + ((and (integer? x1) (integer? x2)) + (int+ x1 x2)) + (else + (let* ((d1 (denominator x1)) + (d2 (denominator x2)) + (g (gcd d1 d2)) + (s1 (quotient d2 g)) + (s2 (quotient d1 g))) + (/ (+ (* s1 (numerator x1)) + (* s2 (numerator x2))) + (* d1 s1)))))) + (xs + (let loop ((xs xs) + (s 0)) + (if (null? xs) + s + (loop (cdr xs) + (+ s (car xs)))))))) + + + (define * + (case-lambda + ((x1 x2) + (cond + ((and (integer? x1) (integer? x2)) + (int* x1 x2)) + (else + (/ (* (numerator x1) (numerator x2)) + (* (denominator x1) (denominator x2)))))) + (xs + (let loop ((xs xs) + (p 1)) + (if (null? xs) + p + (loop (cdr xs) + (* p (car xs)))))))) + + + (define - + (case-lambda + ((z) + (cond + ((small-int? z) + (call-builtin sub 0 z)) + ((boxed-int? z) + (make-boxed-int (not (positive? z)) (boxed-int-digits z))) + (else + (/ (- (numerator z)) + (denominator z))))) + ((z1 z2) + (cond + ((and (integer? z1) (integer? z2)) + (int- z1 z2)) + (else (+ z1 (- z2))))) + ((z1 . zs) + (let loop ((zs zs) + (d z1)) + (if (null? zs) + d + (loop (cdr zs) + (- d (car zs)))))))) + + + (define (normalize-quotient q) + (when (negative? d) + (set! q (make-quotient (- (numerator q)) + (- (denominator q))))) + (let* ((n (numerator q)) + (d (denominator q)) + (g (gcd n d))) + (make-quotient (quotient n g) + (quotient d g)))) + + + (define / + (case-lambda + ((z) + (/ 1 z)) + ((z1 z2) + (cond + ((and (integer? z1) (integer? z2)) + (when (negative? z2) + (set! z1 (- z1)) + (set! z2 (- z2))) + (let ((g (gcd z1 z2))) + (make-quotient (quotient z1 g) + (quotient z2 g)))) + (else + (* z1 + (/ (denominator z2) + (numerator z2)))))) + ((z1 . zs) + (let loop ((zs zs) + (q z1)) + (if (null? zs) + q + (loop (cdr zs) + (/ q (car zs)))))))) + + + (define (abs x) + (if (negative? x) + (- x) + x)) + + + (define (floor x) + (if (integer? x) + x + (floor-quotient (numerator x) + (denominator x)))) + + + (define (ceiling x) + (if (integer? x) + x + (+ 1 (floor x)))) + + + (define (truncate x) + (if (integer? x) + x + (truncate-quotient (numerator x) + (denominator x)))) + + + (define (round x) + (define d (denominator x)) + (define-values (q r) (floor-quotient (numerator x) + d)) + (cond + ((< (* 2 r) d) + q) + ((= (* 2 r) d) ; round to even + (if (even? q) + q + (+ 1 q))) + (else + (+ 1 q)))) + + + (define (square z) + (* z z)) + + + (define (exact-integer-sqrt k) + (if (zero? k) + (values 0 0) + (let loop ((x (/ k 4))) ; initial estimate + (define y (/ (+ x (/ k x)) + 2)) ; 1/2 (x + k/x) + (if (> 1 (abs (- x y))) + (let ((s (truncate y))) + (values s (- k (* s s)))) + (loop y))))) + + + (define (expt x y) + (unless (integer? y) + (error "only integer exponents are supported for now")) + (cond + ((zero? y) 1) + ((even? y) + (expt (square x) (quotient y 2))) + (else + (* x (expt x (- y 1))))))) -- cgit v1.3.1