diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2018-03-08 06:31:51 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2018-03-08 06:31:51 -0800 |
commit | 968e13cbbda2e9fc8a7e8d91cd35d4ac93c695b9 (patch) | |
tree | 64a21f73c14e10b010c02cee1651b7ab4fa73838 /mpi | |
parent | 18bd289d8deadce78123cc54f3730b9d78883f22 (diff) | |
download | txr-968e13cbbda2e9fc8a7e8d91cd35d4ac93c695b9.tar.gz txr-968e13cbbda2e9fc8a7e8d91cd35d4ac93c695b9.tar.bz2 txr-968e13cbbda2e9fc8a7e8d91cd35d4ac93c695b9.zip |
bugfix: broken single-digit bignum multiplication.
* mpi/mpi.c (s_mp_mul_d): The test used for deciding
whether or not the multiplication will carry, and possibly
needs another digit of space, is broken. There are situations
in which a carry occurs (k > 0) in spite of the test being
negative. We code this the way it should have been done in
the first place: resize the object when carry actually occurs.
This still avoids calling s_mp_pad unless absolutely
necessary, as the removed comment says. Also, in the carry
case, we need not try to clamp away leading zeros.
Diffstat (limited to 'mpi')
-rw-r--r-- | mpi/mpi.c | 27 |
1 files changed, 9 insertions, 18 deletions
@@ -3302,20 +3302,7 @@ mp_err s_mp_mul_d(mp_int *a, mp_digit d) mp_err res; mp_digit *dp = DIGITS(a); - /* Single-digit multiplication will increase the precision of the - * output by at most one digit. However, we can detect when this - * will happen -- if the high-order digit of a, times d, gives a - * two-digit result, then the precision of the result will increase; - * otherwise it won't. We use this fact to avoid calling s_mp_pad() - * unless absolutely necessary. - */ max = USED(a); - w = dp[max - 1] * convert(mp_word, d); - if (CARRYOUT(w) != 0) { - if ((res = s_mp_pad(a, max + 1)) != MP_OKAY) - return res; - dp = DIGITS(a); - } for (ix = 0; ix < max; ix++) { w = dp[ix] * convert(mp_word, d) + k; @@ -3323,16 +3310,20 @@ mp_err s_mp_mul_d(mp_int *a, mp_digit d) k = CARRYOUT(w); } - /* If there is a precision increase, take care of it here; the above - * test guarantees we have enough storage to do this safely. + /* If there is a carry out, we must ensure + * we have enough storage for the extra digit. + * If there is carry, there are no leading zeros + * don't waste time calling s_mp_clamp. */ if (k) { - dp[max] = k; + if ((res = s_mp_pad(a, max + 1)) != MP_OKAY) + return res; + DIGIT(a, max) = k; USED(a) = max + 1; + } else { + s_mp_clamp(a); } - s_mp_clamp(a); - return MP_OKAY; } |