diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2011-12-13 17:36:08 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2011-12-13 17:36:08 -0800 |
commit | ef47dfe4fcb7c1be369ae83221386b9da6474a1e (patch) | |
tree | a2ac264811c80ad085eea5ea725b3bb6be8ba751 /arith.c | |
parent | 5d0f219ab35f9e214a063e968286ba01f4b54dbf (diff) | |
download | txr-ef47dfe4fcb7c1be369ae83221386b9da6474a1e.tar.gz txr-ef47dfe4fcb7c1be369ae83221386b9da6474a1e.tar.bz2 txr-ef47dfe4fcb7c1be369ae83221386b9da6474a1e.zip |
* arith.c (highest_bit): Linkage changed to static.
(abso, isqrt): New functions.
(isqrt_fixnum): New static function.
* eval.c (eval_init): Registered abs, sqrt and numberp instrinsics.
* lib.c (numberp): New function.
* lib.h (numberp, abso, isqrt): Declared.
* mpi-patches/series: New patch added.
* mpi-patches/faster-square-root: New patch added.
* txr.1: Documentation stubs for new functions.
Diffstat (limited to 'arith.c')
-rw-r--r-- | arith.c | 44 |
1 files changed, 43 insertions, 1 deletions
@@ -84,7 +84,7 @@ static val normalize(val bignum) } } -int highest_bit(int_ptr_t n) +static int highest_bit(int_ptr_t n) { #if SIZEOF_PTR == 8 if (n & 0x7FFFFFFF00000000) { @@ -414,6 +414,18 @@ val neg(val anum) } } +val abso(val anum) +{ + if (bignump(anum)) { + val n = make_bignum(); + mp_abs(mp(anum), mp(n)); + return n; + } else { + cnum n = c_num(anum); + return num(n < 0 ? n : n); + } +} + val mul(val anum, val bnum) { int tag_a = tag(anum); @@ -890,6 +902,36 @@ val expt(val anum, val bnum) abort(); } +static int_ptr_t isqrt_fixnum(int_ptr_t a) +{ + int_ptr_t mask = (int_ptr_t) 1 << (highest_bit(a) / 2); + int_ptr_t root = 0; + + for (; mask != 0; mask >>= 1) { + int_ptr_t next_guess = root | mask; + if (next_guess * next_guess <= a) + root = next_guess; + } + + return root; +} + +val isqrt(val anum) +{ + if (fixnump(anum)) { + cnum a = c_num(anum); + if (a < 0) + uw_throw(error_s, lit("sqrt: negative operand")); + return num_fast(isqrt_fixnum(c_num(anum))); + } else if (bignump(anum)) { + val n = make_bignum(); + if (mp_sqrt(mp(anum), mp(n)) != MP_OKAY) + uw_throw(error_s, lit("sqrt: negative operand")); + return normalize(n); + } + uw_throwf(error_s, lit("sqrt: invalid operand ~s"), anum, nao); +} + void arith_init(void) { mp_init(&NUM_MAX_MP); |