Don't pass around w as a KrkLong

We only shifting up to size_t bits anyway; expose the internal
size_t-based shifting, use that in these functions, and stop
allocating additional KrkLongs for the `w` values.

Since we only do this a few times and the values were very small,
this has minimal impact but does simplify the code a bit.
This commit is contained in:
K. Lange 2024-01-13 16:57:07 +09:00
parent 9590df3ef0
commit 6e8aa9bee6

View File

@ -1494,40 +1494,42 @@ BASIC_BIN_OP(or, krk_long_or)
BASIC_BIN_OP(xor,krk_long_xor)
BASIC_BIN_OP(and,krk_long_and)
static void _krk_long_lshift(krk_long out, krk_long val, krk_long shift) {
if (krk_long_sign(shift) < 0) { krk_runtimeError(vm.exceptions->valueError, "negative shift count"); return; }
if (krk_long_sign(shift) == 0) {
static void _krk_long_lshift_z(krk_long out, krk_long val, size_t amount) {
if (amount == 0) {
krk_long_clear(out);
krk_long_init_copy(out,val);
return;
}
int64_t amount = krk_long_medium(shift);
int64_t count = _bits_in(val);
krk_long_clear(out);
if (count == 0) return;
for (int64_t i = count - 1; i >= 0; i--) {
if (_bit_is_set(val,i)) krk_long_bit_set(out,i + amount);
for (size_t i = count; i > 0; i--) {
if (_bit_is_set(val,i - 1)) krk_long_bit_set(out,i - 1 + amount);
}
if (krk_long_sign(val) < 0) krk_long_set_sign(out,-1);
}
static void _krk_long_rshift(krk_long out, krk_long val, krk_long shift) {
static void _krk_long_lshift(krk_long out, krk_long val, krk_long shift) {
if (krk_long_sign(shift) < 0) { krk_runtimeError(vm.exceptions->valueError, "negative shift count"); return; }
if (krk_long_sign(shift) == 0) {
int64_t amount = krk_long_medium(shift);
_krk_long_lshift_z(out,val,amount);
}
static void _krk_long_rshift_z(krk_long out, krk_long val, size_t amount) {
if (amount == 0) {
krk_long_clear(out);
krk_long_init_copy(out,val);
return;
}
int64_t amount = krk_long_medium(shift);
int64_t count = _bits_in(val);
krk_long_clear(out);
if (count == 0) return;
for (int64_t i = count - 1; i >= amount; i--) {
for (size_t i = count - 1; i >= amount; i--) {
if (_bit_is_set(val,i)) krk_long_bit_set(out,i - amount);
}
@ -1539,6 +1541,12 @@ static void _krk_long_rshift(krk_long out, krk_long val, krk_long shift) {
}
}
static void _krk_long_rshift(krk_long out, krk_long val, krk_long shift) {
if (krk_long_sign(shift) < 0) { krk_runtimeError(vm.exceptions->valueError, "negative shift count"); return; }
int64_t amount = krk_long_medium(shift);
_krk_long_rshift_z(out, val, amount);
}
static void _krk_long_mod(krk_long out, krk_long a, krk_long b) {
if (krk_long_sign(b) == 0) { krk_runtimeError(vm.exceptions->valueError, "integer division or modulo by zero"); return; }
krk_long garbage;
@ -2156,45 +2164,36 @@ static digit_t * dec_mul(const digit_t * a, size_t a_width, const digit_t * b, s
* but not a whole lot in the long run, and this implementation is
* considerably simpler without the cache.
*
* @param w Power to raise 2 to, as a KrkLong.
* @param w Power to raise 2 to.
* @param sizeOut Resulting size of the huge decimal.
* @returns A huge decimal representing 2 ** w.
*/
static digit_t * dec_two_raised(KrkLong * w, size_t * sizeOut) {
if (w->width == 0 || (w->width == 1 && w->digits[0] <= 29)) {
static digit_t * dec_two_raised(size_t w, size_t * sizeOut) {
if (w <= 29) {
*sizeOut = 1;
digit_t * out = malloc(DEC_DIGIT_SIZE);
out[0] = 1 << (w->width == 0 ? 0 : w->digits[0]);
out[0] = 1 << w;
return out;
} else {
/* w2 = w >> 1 */
KrkLong w2;
KrkLong one;
krk_long_init_si(&w2, 0);
krk_long_init_si(&one, 1);
_krk_long_rshift(&w2, w, &one);
size_t w2 = w >> 1;
/* t = Decimal(1 << w2) */
size_t tSize;
digit_t * t = dec_two_raised(&w2, &tSize);
digit_t * t = dec_two_raised(w2, &tSize);
if ((w->digits[0] & 1) == 0) {
if ((w & 1) == 0) {
/* Result = t * t */
krk_long_clear_many(&one, &w2, NULL);
digit_t * result = dec_mul(t, tSize, t, tSize, sizeOut);
free(t);
return result;
} else {
/* wmw2 = w - w2 */
KrkLong wmw2;
krk_long_init_si(&wmw2, 0);
krk_long_sub(&wmw2, w, &w2);
krk_long_clear_many(&one, &w2, NULL);
size_t wmw2 = w - w2;
/* right = 1 << wmw2 */
size_t rightSize;
digit_t * right = dec_two_raised(&wmw2, &rightSize);
krk_long_clear(&wmw2);
digit_t * right = dec_two_raised(wmw2, &rightSize);
/* result = t * right */
digit_t * result = dec_mul(t, tSize, right, rightSize, sizeOut);
@ -2212,16 +2211,16 @@ static digit_t * dec_two_raised(KrkLong * w, size_t * sizeOut) {
* @c digit_t huge decimal digits, storing the size in @p sizeOut.
*
* @param n KrkLong to convert.
* @param w Bitwidth of @p n as a KrkLong.
* @param w Bitwidth of @p n.
* @param sizeOut Resulting size of the huge decimal.
* @returns Huge decimal of equivalent value.
*/
static digit_t * long_to_dec_inner(KrkLong * n, KrkLong * w, size_t * sizeOut) {
static digit_t * long_to_dec_inner(KrkLong * n, size_t w, size_t * sizeOut) {
if (n->width == 0) {
*sizeOut = 1;
return calloc(1,DEC_DIGIT_SIZE);
}
if (w->width == 1 && w->digits[0] <= 29) {
if (w <= 29) {
*sizeOut = 1;
digit_t * out = malloc(DEC_DIGIT_SIZE);
out[0] = n->digits[0];
@ -2230,33 +2229,29 @@ static digit_t * long_to_dec_inner(KrkLong * n, KrkLong * w, size_t * sizeOut) {
size_t aSize, bSize, cSize;
digit_t * a, * b, * c;
KrkLong w2, hi, lo, tmp;
krk_long_init_many(&w2, &hi, &lo, &tmp, NULL);
KrkLong one;
krk_long_init_si(&one, 1);
KrkLong hi, lo, tmp;
krk_long_init_many(&hi, &lo, &tmp, NULL);
/* w2 = w >> 1 */
_krk_long_rshift(&w2, w, &one);
size_t w2 = w >> 1;
/* hi = n >> w2 */
_krk_long_rshift(&hi, n, &w2);
/* tmp = hi >> w2 */
_krk_long_lshift(&tmp, &hi, &w2);
/* lo = n - (hi >> w2) */
_krk_long_rshift_z(&hi, n, w2);
/* tmp = hi << w2 */
_krk_long_lshift_z(&tmp, &hi, w2);
/* lo = n - (hi << w2) */
krk_long_sub(&lo, n, &tmp);
krk_long_clear_many(&one, &tmp, NULL);
/* tmp = w - w2 */
krk_long_sub(&tmp, w, &w2);
krk_long_clear_many(&tmp, NULL);
/* a = Dec(hi) */
a = long_to_dec_inner(&hi, &tmp, &aSize);
krk_long_clear_many(&hi, &tmp, NULL);
a = long_to_dec_inner(&hi, w - w2, &aSize);
krk_long_clear_many(&hi, NULL);
/* b = Dec(1 << w2) */
b = dec_two_raised(&w2, &bSize);
b = dec_two_raised(w2, &bSize);
/* c = a * b */
c = dec_mul(a, aSize, b, bSize, &cSize);
free(a);
free(b);
/* a = Dec(lo) */
a = long_to_dec_inner(&lo, &w2, &aSize);
krk_long_clear_many(&lo,&w2,NULL);
a = long_to_dec_inner(&lo, w2, &aSize);
krk_long_clear_many(&lo,NULL);
/* result = a + c */
digit_t * result = dec_add(a, aSize, c, cSize, sizeOut);
free(a);
@ -2281,17 +2276,11 @@ KRK_Method(long,__repr__) {
krk_long_set_sign(&abs, 1);
/* Calculate bit width for halving */
size_t bits = _bits_in(&abs);
KrkLong w;
krk_long_init_ui(&w, bits);
size_t w = _bits_in(&abs);
/* Convert to big decimal digits */
size_t size;
digit_t * digits = long_to_dec_inner(&abs, &w, &size);
/* We don't need to clear abs since its digits are our digits, but
* we need to clean up w even if it is pretty small... */
krk_long_clear(&w);
digit_t * digits = long_to_dec_inner(&abs, w, &size);
/* Count number of leading zeros */
int leading = 0;
@ -2300,7 +2289,7 @@ KRK_Method(long,__repr__) {
leading += 1;
}
/* Allocate spcae for output */
/* Allocate space for output */
char * out = malloc(size * DEC_DIGIT_CNT + 1 - leading + inv);
char * writer = out;