summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-06-14 22:02:11 -0700
committerKaz Kylheku <kaz@kylheku.com>2017-06-14 22:02:11 -0700
commitd8a8c64b0b15bfbe1af29d3905325037135edc00 (patch)
tree0c57aa9d68c365abd1053f997e978e8970caf3b1
parentbddc5f5c9981a3dd1bb04fb35a50bcccb4a08d39 (diff)
downloadtxr-d8a8c64b0b15bfbe1af29d3905325037135edc00.tar.gz
txr-d8a8c64b0b15bfbe1af29d3905325037135edc00.tar.bz2
txr-d8a8c64b0b15bfbe1af29d3905325037135edc00.zip
bugfix: sign-extend broken for bignums.
* arith.c (sign_extend): After taking the two's complement which works at the granularity of digits, not the exact number of bits, we must truncate the number to the exact number of bits before negating. Otherwise we end up with an excessively large value. For instance if a bignum like #x80... is sign extended tightly to the upper 1 bit, the resulting value is something like #-xFFFF80..., rather than #x-80... as it should be. There are extra 1 bits padding up to the bignum digit. These must be chopped away.
-rw-r--r--arith.c1
1 files changed, 1 insertions, 0 deletions
diff --git a/arith.c b/arith.c
index 7ebe0819..537c1a0d 100644
--- a/arith.c
+++ b/arith.c
@@ -2405,6 +2405,7 @@ val sign_extend(val n, val nbits)
{
val out = make_ubignum();
mp_2comp(mp(ntrunc), mp(out), mp(ntrunc)->used);
+ mp_trunc(mp(out), mp(out), c_num(nbits));
mp_neg(mp(out), mp(out));
return normalize(out);
}