diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2012-09-17 07:37:40 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2012-09-17 07:37:40 -0700 |
commit | 01628a8244053ced7dd0f20e13e4ce3ff3e81481 (patch) | |
tree | f92cca343580e6d1f6035482f3eaa8c2aae6a3cf /arith.c | |
parent | e27921f29d6b78d5c868d9160e5c12e9a49b4f97 (diff) | |
download | txr-01628a8244053ced7dd0f20e13e4ce3ff3e81481.tar.gz txr-01628a8244053ced7dd0f20e13e4ce3ff3e81481.tar.bz2 txr-01628a8244053ced7dd0f20e13e4ce3ff3e81481.zip |
* arith.c (highest_significant_bit): New static function.
(comp_clamp): Bugfix: avoid shifting left into sign bit. Function
renamed to comp_trunc.
(logtrunc, ash): New functions.
* eval.c (eval_init): Registered logtrunc and ash intrinsics.
* lib.h (logtrunc, ash): Declared.
* mpi-patches/add-bitops (s_highest_bit_mp): Forward declaration for
added.
(mp_clamp_comp): Bugfix in handling remainder bits. Function
renamed to mp_trunc_comp.
(mp_trunc, mp_shift): New functions.
Diffstat (limited to 'arith.c')
-rw-r--r-- | arith.c | 120 |
1 files changed, 116 insertions, 4 deletions
@@ -268,6 +268,13 @@ int highest_bit(int_ptr_t n) abort(); } +static int highest_significant_bit(int_ptr_t n) +{ + if (n >= 0) + return highest_bit(n); + return highest_bit(n ^ INT_PTR_MAX); +} + val plus(val anum, val bnum) { tail: @@ -1611,7 +1618,7 @@ bad: uw_throwf(error_s, lit("logxor: operation failed on ~s ~s"), a, b, nao); } -static val comp_clamp(val a, val bits) +static val comp_trunc(val a, val bits) { cnum an, bn; val b; @@ -1626,7 +1633,7 @@ static val comp_clamp(val a, val bits) switch (type(a)) { case NUM: an = c_num(a); - if (bn <= num_bits) { + if (bn < num_bits) { cnum mask = num_mask >> (num_bits - bn); return num_fast((an & mask) ^ mask); } @@ -1634,7 +1641,7 @@ static val comp_clamp(val a, val bits) /* fallthrough */ case BGNUM: b = make_bignum(); - if (mp_clamp_comp(mp(a), mp(b), bn) != MP_OKAY) + if (mp_trunc_comp(mp(a), mp(b), bn) != MP_OKAY) goto bad; return normalize(b); default: @@ -1656,7 +1663,7 @@ val logcomp(val a, val bits) val b; if (bits) - return comp_clamp(a, bits); + return comp_trunc(a, bits); switch (type(a)) { case NUM: @@ -1674,6 +1681,111 @@ bad: uw_throwf(error_s, lit("logcomp: operation failed on ~s"), a, nao); } +val logtrunc(val a, val bits) +{ + cnum an, bn; + val b; + const cnum num_mask = (NUM_MAX << 1) | 1; + const int num_bits = CHAR_BIT * sizeof (cnum) - 2; + + if (!fixnump(bits)) + goto bad2; + + bn = c_num(bits); + + switch (type(a)) { + case NUM: + an = c_num(a); + if (bn <= num_bits) { + cnum mask = num_mask >> (num_bits - bn); + return num_fast(an & mask); + } + a = bignum(an); + /* fallthrough */ + case BGNUM: + b = make_bignum(); + if (mp_trunc(mp(a), mp(b), bn) != MP_OKAY) + goto bad; + return normalize(b); + default: + goto bad3; + } + +bad: + uw_throwf(error_s, lit("logtrunc: operation failed on ~s"), a, nao); + +bad2: + uw_throwf(error_s, lit("logtrunc: bits value ~s is not a fixnum"), bits, nao); + +bad3: + uw_throwf(error_s, lit("logtrunc: non-integral operand ~s"), a, nao); +} + +val ash(val a, val bits) +{ + cnum an, bn; + val b; + int hb; + const int num_bits = CHAR_BIT * sizeof (cnum) - 2; + + if (!fixnump(bits)) + goto bad2; + + bn = c_num(bits); + + if (bn == 0) { + switch (type(a)) { + case NUM: + case BGNUM: + return a; + default: + goto bad3; + } + } else if (bn > 0) { + switch (type(a)) { + case NUM: + an = c_num(a); + hb = highest_significant_bit(an); + if (bn + hb < num_bits) + return num_fast(an << bn); + a = bignum(an); + /* fallthrough */ + case BGNUM: + b = make_bignum(); + if (mp_shift(mp(a), mp(b), bn) != MP_OKAY) + goto bad; + return normalize(b); + default: + goto bad3; + } + } else { + switch (type(a)) { + case NUM: + an = c_num(a); + if (bn <= num_bits) + return num_fast(an >> -bn); + return num_fast(an >> num_bits); + case BGNUM: + b = make_bignum(); + if (mp_shift(mp(a), mp(b), bn) != MP_OKAY) + goto bad; + return normalize(b); + default: + goto bad3; + } + + } + +bad: + uw_throwf(error_s, lit("ashift: operation failed on ~s"), a, nao); + +bad2: + uw_throwf(error_s, lit("ashift: bits value ~s is not a fixnum"), bits, nao); + +bad3: + uw_throwf(error_s, lit("ashift: non-integral operand ~s"), a, nao); +} + void arith_init(void) { mp_init(&NUM_MAX_MP); |