414 lines
12 KiB
Scheme
414 lines
12 KiB
Scheme
|
|
(let ()
|
|
|
|
(define bignum?
|
|
; FIXME: temporary definition. Compiler should be made aware
|
|
; of numeric representation once it's stable enough.
|
|
(lambda (x)
|
|
(foreign-call "ikrt_isbignum" x)))
|
|
|
|
(define binary+
|
|
(lambda (x y)
|
|
(cond
|
|
[(fixnum? x)
|
|
(cond
|
|
[(fixnum? y)
|
|
(foreign-call "ikrt_fxfxplus" x y)]
|
|
[(bignum? y)
|
|
(foreign-call "ikrt_fxbnplus" x y)]
|
|
[else
|
|
(error '+ "~s is not a number" y)])]
|
|
[(bignum? x)
|
|
(cond
|
|
[(fixnum? y)
|
|
(foreign-call "ikrt_fxbnplus" y x)]
|
|
[(bignum? y)
|
|
(foreign-call "ikrt_bnbnplus" x y)]
|
|
[else
|
|
(error '+ "~s is not a number" y)])]
|
|
[else (error '+ "~s is not a number" x)])))
|
|
|
|
(define binary-logand
|
|
(lambda (x y)
|
|
(cond
|
|
[(fixnum? x)
|
|
(cond
|
|
[(fixnum? y) (#%$fxlogand x y)]
|
|
[(bignum? y)
|
|
(foreign-call "ikrt_fxbnlogand" x y)]
|
|
[else
|
|
(error 'logand "~s is not a number" y)])]
|
|
[(bignum? x)
|
|
(cond
|
|
[(fixnum? y)
|
|
(foreign-call "ikrt_fxbnlogand" y x)]
|
|
[(bignum? y)
|
|
(foreign-call "ikrt_bnbnlogand" x y)]
|
|
[else
|
|
(error 'logand "~s is not a number" y)])]
|
|
[else (error 'logand "~s is not a number" x)])))
|
|
|
|
|
|
(define binary-
|
|
(lambda (x y)
|
|
(cond
|
|
[(fixnum? x)
|
|
(cond
|
|
[(fixnum? y)
|
|
(foreign-call "ikrt_fxfxminus" x y)]
|
|
[(bignum? y)
|
|
(foreign-call "ikrt_fxbnminus" x y)]
|
|
[else
|
|
(error '- "~s is not a number" y)])]
|
|
[(bignum? x)
|
|
(cond
|
|
[(fixnum? y)
|
|
(foreign-call "ikrt_bnfxminus" x y)]
|
|
[(bignum? y)
|
|
(foreign-call "ikrt_bnbnminus" x y)]
|
|
[else
|
|
(error '- "~s is not a number" y)])]
|
|
[else (error '- "~s is not a number" x)])))
|
|
|
|
(define binary*
|
|
(lambda (x y)
|
|
(cond
|
|
[(fixnum? x)
|
|
(cond
|
|
[(fixnum? y)
|
|
(foreign-call "ikrt_fxfxmult" x y)]
|
|
[(bignum? y)
|
|
(foreign-call "ikrt_fxbnmult" x y)]
|
|
[else
|
|
(error '* "~s is not a number" y)])]
|
|
[(bignum? x)
|
|
(cond
|
|
[(fixnum? y)
|
|
(foreign-call "ikrt_fxbnmult" y x)]
|
|
[(bignum? y)
|
|
(foreign-call "ikrt_bnbnmult" x y)]
|
|
[else
|
|
(error '* "~s is not a number" y)])]
|
|
[else (error '* "~s is not a number" x)])))
|
|
|
|
(define +
|
|
(case-lambda
|
|
[(x y) (binary+ x y)]
|
|
[(x y z) (binary+ (binary+ x y) z)]
|
|
[(a)
|
|
(cond
|
|
[(fixnum? a) a]
|
|
[(bignum? a) a]
|
|
[else (error '+ "~s is not a number" a)])]
|
|
[() 0]
|
|
[(a b c d . e*)
|
|
(let f ([ac (binary+ (binary+ (binary+ a b) c) d)]
|
|
[e* e*])
|
|
(cond
|
|
[(null? e*) ac]
|
|
[else (f (binary+ ac (car e*)) (cdr e*))]))]))
|
|
|
|
(define logand
|
|
(case-lambda
|
|
[(x y) (binary-logand x y)]
|
|
[(x y z) (binary-logand (binary-logand x y) z)]
|
|
[(a)
|
|
(cond
|
|
[(fixnum? a) a]
|
|
[(bignum? a) a]
|
|
[else (error 'logand "~s is not a number" a)])]
|
|
[() -1]
|
|
[(a b c d . e*)
|
|
(let f ([ac (binary-logand (binary-logand (binary-logand a b) c) d)]
|
|
[e* e*])
|
|
(cond
|
|
[(null? e*) ac]
|
|
[else (f (binary-logand ac (car e*)) (cdr e*))]))]))
|
|
|
|
(define -
|
|
(case-lambda
|
|
[(x y) (binary- x y)]
|
|
[(x y z) (binary- (binary- x y) z)]
|
|
[(a) (binary- 0 a)]
|
|
[(a b c d . e*)
|
|
(let f ([ac (binary- (binary- (binary- a b) c) d)]
|
|
[e* e*])
|
|
(cond
|
|
[(null? e*) ac]
|
|
[else (f (binary- ac (car e*)) (cdr e*))]))]))
|
|
|
|
(define *
|
|
(case-lambda
|
|
[(x y) (binary* x y)]
|
|
[(x y z) (binary* (binary* x y) z)]
|
|
[(a)
|
|
(cond
|
|
[(fixnum? a) a]
|
|
[(bignum? a) a]
|
|
[else (error '* "~s is not a number" a)])]
|
|
[() 1]
|
|
[(a b c d . e*)
|
|
(let f ([ac (binary* (binary* (binary* a b) c) d)]
|
|
[e* e*])
|
|
(cond
|
|
[(null? e*) ac]
|
|
[else (f (binary* ac (car e*)) (cdr e*))]))]))
|
|
|
|
(define expt
|
|
(lambda (n m)
|
|
(cond
|
|
[(#%$fxzero? m) 1]
|
|
[(#%$fxzero? (#%$fxlogand m 1))
|
|
(expt (binary* n n) (#%$fxsra m 1))]
|
|
[else
|
|
(binary* n (expt (binary* n n) (#%$fxsra m 1)))])))
|
|
|
|
|
|
(define number?
|
|
(lambda (x)
|
|
(or (fixnum? x)
|
|
(bignum? x))))
|
|
|
|
(define positive-bignum?
|
|
(lambda (x)
|
|
(foreign-call "ikrt_positive_bn" x)))
|
|
|
|
|
|
(define even-bignum?
|
|
(lambda (x) (error 'even-bignum? "not implemented")))
|
|
|
|
(define number->string
|
|
(lambda (x)
|
|
(cond
|
|
[(fixnum? x) (fixnum->string x)]
|
|
[(bignum? x) (foreign-call "ikrt_bntostring" x)]
|
|
[else (error 'number->string "~s is not a number" x)])))
|
|
|
|
(define-syntax mk<
|
|
(syntax-rules ()
|
|
[(_ name fxfx< fxbn< bnfx< bnbn<)
|
|
(let ()
|
|
(define err
|
|
(lambda (x) (error 'name "~s is not a number" x)))
|
|
(define fxloopt
|
|
(lambda (x y ls)
|
|
(cond
|
|
[(fixnum? y)
|
|
(if (null? ls)
|
|
(fxfx< x y)
|
|
(if (fxfx< x y)
|
|
(fxloopt y (car ls) (cdr ls))
|
|
(loopf (car ls) (cdr ls))))]
|
|
[(bignum? y)
|
|
(if (null? ls)
|
|
(fxbn< x y)
|
|
(if (fxbn< x y)
|
|
(bnloopt y (car ls) (cdr ls))
|
|
(loopf (car ls) (cdr ls))))]
|
|
[else (err y)])))
|
|
(define bnloopt
|
|
(lambda (x y ls)
|
|
(cond
|
|
[(fixnum? y)
|
|
(if (null? ls)
|
|
(bnfx< x y)
|
|
(if (bnfx< x y)
|
|
(fxloopt y (car ls) (cdr ls))
|
|
(loopf (car ls) (cdr ls))))]
|
|
[(bignum? y)
|
|
(if (null? ls)
|
|
(bnbn< x y)
|
|
(if (bnbn< x y)
|
|
(bnloopt y (car ls) (cdr ls))
|
|
(loopf (car ls) (cdr ls))))]
|
|
[else (err y)])))
|
|
(define loopf
|
|
(lambda (x ls)
|
|
(cond
|
|
[(number? x)
|
|
(or (null? ls) (loopf (car ls) (cdr ls)))]
|
|
[else (err x)])))
|
|
(case-lambda
|
|
[(x y)
|
|
(cond
|
|
[(fixnum? x)
|
|
(cond
|
|
[(fixnum? y) (fxfx< x y)]
|
|
[(bignum? y) (fxbn< x y)]
|
|
[else (err y)])]
|
|
[(bignum? x)
|
|
(cond
|
|
[(fixnum? y) (bnfx< x y)]
|
|
[(bignum? y) (bnbn< x y)]
|
|
[else (err y)])]
|
|
[else (err x)])]
|
|
[(x y z)
|
|
(cond
|
|
[(fixnum? x)
|
|
(cond
|
|
[(fixnum? y)
|
|
(cond
|
|
[(fixnum? z) (and (fxfx< x y) (fxfx< y z))]
|
|
[(bignum? z)
|
|
(and (fxfx< x y) (fxbn< y z))]
|
|
[else (err z)])]
|
|
[(bignum? y)
|
|
(cond
|
|
[(fixnum? z) #f]
|
|
[(bignum? z)
|
|
(and (fxbn< x y) (bnbn< y z))]
|
|
[else (err z)])]
|
|
[else (err y)])]
|
|
[(bignum? x)
|
|
(cond
|
|
[(fixnum? y)
|
|
(cond
|
|
[(fixnum? z) (and (fxfx< y z) (bnfx< x y))]
|
|
[(bignum? z)
|
|
(and (bnfx< x y) (bnfx< y z))]
|
|
[else (err z)])]
|
|
[(bignum? y)
|
|
(cond
|
|
[(fixnum? z) (and (bnfx< y z) (bnbn< x y))]
|
|
[(bignum? z) (and (bnbn< x y) (bnbn< y z))]
|
|
[else (err z)])]
|
|
[else (err y)])]
|
|
[else (err x)])]
|
|
[(x) (if (number? x) #t (err x))]
|
|
[(x y . ls)
|
|
(cond
|
|
[(fixnum? x) (fxloopt x y ls)]
|
|
[(bignum? x) (bnloopt x y ls)]
|
|
[else (err x)])]))]))
|
|
|
|
(define-syntax false (syntax-rules () [(_ x y) #f]))
|
|
(define-syntax bnbncmp
|
|
(syntax-rules ()
|
|
[(_ x y cmp)
|
|
(cmp (foreign-call "ikrt_bnbncomp" x y) 0)]))
|
|
(define-syntax bnbn= (syntax-rules () [(_ x y) (bnbncmp x y #%$fx=)]))
|
|
(define-syntax bnbn< (syntax-rules () [(_ x y) (bnbncmp x y #%$fx<)]))
|
|
(define-syntax bnbn> (syntax-rules () [(_ x y) (bnbncmp x y #%$fx>)]))
|
|
(define-syntax bnbn<= (syntax-rules () [(_ x y) (bnbncmp x y #%$fx<=)]))
|
|
(define-syntax bnbn>= (syntax-rules () [(_ x y) (bnbncmp x y #%$fx>=)]))
|
|
(define-syntax fxbn< (syntax-rules () [(_ x y) (positive-bignum? y)]))
|
|
(define-syntax bnfx< (syntax-rules () [(_ x y) (not (positive-bignum? x))]))
|
|
(define-syntax fxbn> (syntax-rules () [(_ x y) (not (positive-bignum? y))]))
|
|
(define-syntax bnfx> (syntax-rules () [(_ x y) (positive-bignum? x)]))
|
|
|
|
|
|
|
|
(primitive-set! '+ +)
|
|
(primitive-set! '- -)
|
|
(primitive-set! '* *)
|
|
(primitive-set! '= (mk< = #%$fx= false false bnbn=))
|
|
(primitive-set! '< (mk< < #%$fx< fxbn< bnfx< bnbn<))
|
|
(primitive-set! '> (mk< > #%$fx> fxbn> bnfx> bnbn>))
|
|
(primitive-set! '<= (mk< <= #%$fx<= fxbn< bnfx< bnbn<=))
|
|
(primitive-set! '>= (mk< >= #%$fx>= fxbn> bnfx> bnbn>=))
|
|
(primitive-set! 'logand logand)
|
|
(primitive-set! 'number? number?)
|
|
(primitive-set! 'number->string number->string)
|
|
|
|
(primitive-set! 'add1
|
|
(lambda (x)
|
|
(cond
|
|
[(fixnum? x)
|
|
(foreign-call "ikrt_fxfxplus" x 1)]
|
|
[(bignum? x)
|
|
(foreign-call "ikrt_fxbnplus" 1 x)]
|
|
[else (error 'add1 "~s is not a number" x)])))
|
|
|
|
(primitive-set! 'sub1
|
|
(lambda (x)
|
|
(cond
|
|
[(fixnum? x)
|
|
(foreign-call "ikrt_fxfxplus" x -1)]
|
|
[(bignum? x)
|
|
(foreign-call "ikrt_fxbnplus" -1 x)]
|
|
[else (error 'sub1 "~s is not a number" x)])))
|
|
|
|
(primitive-set! 'zero?
|
|
(lambda (x)
|
|
(cond
|
|
[(fixnum? x) (eq? x 0)]
|
|
[(bignum? x) #f]
|
|
[else (error 'zero? "~s is not a number" x)])))
|
|
|
|
(primitive-set! 'expt
|
|
(lambda (n m)
|
|
(unless (number? n)
|
|
(error 'expt "~s is not a numebr" n))
|
|
(cond
|
|
[(fixnum? m)
|
|
(if (#%$fx>= m 0)
|
|
(expt n m)
|
|
(error 'expt "power should be positive, got ~s" m))]
|
|
[(bignum? m)
|
|
(cond
|
|
[(eq? n 0) 0]
|
|
[(eq? n 1) 1]
|
|
[(eq? n -1)
|
|
(if (positive-bignum? m)
|
|
(if (even-bignum? m)
|
|
1
|
|
-1)
|
|
(error 'expt "power should be positive, got ~s" m))]
|
|
[else
|
|
(if (positive-bignum? m)
|
|
(error 'expt "(expt ~s ~s) is too big to compute" n m)
|
|
(error 'expt "power should be positive, got ~s" m))])]
|
|
[else (error 'expt "~s is not a number" m)])))
|
|
|
|
(primitive-set! 'quotient
|
|
(lambda (x y)
|
|
(let-values ([(q r) (quotient+remainder x y)])
|
|
q)))
|
|
|
|
(primitive-set! 'remainder
|
|
(lambda (x y)
|
|
(let-values ([(q r) (quotient+remainder x y)])
|
|
r)))
|
|
|
|
(primitive-set! 'quotient+remainder
|
|
(lambda (x y)
|
|
(cond
|
|
[(eq? y 0)
|
|
(error 'quotient+remainder
|
|
"second argument must be non-zero")]
|
|
[(fixnum? x)
|
|
(cond
|
|
[(fixnum? y)
|
|
(values (fxquotient x y)
|
|
(fxremainder x y))]
|
|
[(bignum? y) (values 0 x)]
|
|
[else (error 'quotient+remainder
|
|
"~s is not a number" y)])]
|
|
[(bignum? x)
|
|
(cond
|
|
[(fixnum? y)
|
|
(let ([p (foreign-call "ikrt_bnfxdivrem" x y)])
|
|
(values (car p) (cdr p)))]
|
|
[(bignum? y)
|
|
(let ([p (foreign-call "ikrt_bnbndivrem" x y)])
|
|
(values (car p) (cdr p)))]
|
|
[else (error 'quotient+remainder
|
|
"~s is not a number" y)])]
|
|
[else (error 'quotient+remainder
|
|
"~s is not a number" x)])))
|
|
|
|
(primitive-set! 'positive?
|
|
(lambda (x)
|
|
(cond
|
|
[(fixnum? x) (#%$fx> x 0)]
|
|
[(bignum? x) (positive-bignum? x)]
|
|
[else (error 'positive? "~s is not a number" x)])))
|
|
|
|
(primitive-set! 'negative?
|
|
(lambda (x)
|
|
(cond
|
|
[(fixnum? x) (#%$fx< x 0)]
|
|
[(bignum? x) (not (positive-bignum? x))]
|
|
[else (error 'negative? "~s is not a number" x)])))
|
|
)
|