From eb78f50c666690e3aa26719ca9c8eb7a866edf57 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 8 Jun 2022 11:56:29 -0400 Subject: [PATCH] Working conversion of bignum2 -> string --- include/cyclone/types.h | 2 +- runtime.c | 119 ++++++++++++++++++---------------------- test-bn.scm | 4 ++ 3 files changed, 59 insertions(+), 66 deletions(-) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 2b3eb176..9efb392b 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -887,7 +887,7 @@ typedef struct { // // /* These might fit better in runtime.c? */ #define Cyc_fitsinbignumhalfdigitp(n) (C_BIGNUM_DIGIT_HI_HALF(n) == 0) -// #define C_BIGNUM_DIGIT_LENGTH C_WORD_SIZE +#define C_BIGNUM_DIGIT_LENGTH C_WORD_SIZE #define C_BIGNUM_HALF_DIGIT_LENGTH C_HALF_WORD_SIZE #define C_BIGNUM_BITS_TO_DIGITS(n) \ (((n) + (C_BIGNUM_DIGIT_LENGTH - 1)) / C_BIGNUM_DIGIT_LENGTH) diff --git a/runtime.c b/runtime.c index 24d85cb3..29bdcd75 100644 --- a/runtime.c +++ b/runtime.c @@ -2461,16 +2461,17 @@ static uint32_t bignum_digits_destructive_scale_down(uint32_t *start, uint32_t * return k; } -// TODO: /* Copy all the digits from source to target, obliterating what was * there. If target is larger than source, the most significant * digits will remain untouched. */ -//inline static void bignum_digits_destructive_copy(C_word target, C_word source) -//{ -// C_memcpy(C_bignum_digits(target), C_bignum_digits(source), -// C_wordstobytes(C_bignum_size(source))); -//} +inline static void bignum_digits_destructive_copy(bignum2_type *target, bignum2_type *source) +{ + memcpy(C_bignum_digits(target), + C_bignum_digits(source), + source->num_digits * sizeof(uint32_t)); + //C_wordstobytes(C_bignum_size(source))); +} //TODO: static void bignum2string(void *data, object cont, bignum2_type *bn, int radix) @@ -2480,9 +2481,6 @@ void bignum2string(void *data, object cont, bignum2_type *bn, int radix) int str_length = bignum2_num_digits(bn, radix); int heap_grown; - //printf("DEBUG string length %d\n", bignum2_num_digits(bn, radix)); - //printf("DEBUG radix=%d, nlz = %d\n", radix, radix_shift); - string_type *s = gc_alloc(((gc_thread_data *)data)->heap, sizeof(string_type) + str_length + 1, boolean_f, // OK to populate manually over here @@ -2499,66 +2497,57 @@ void bignum2string(void *data, object cont, bignum2_type *bn, int radix) *index = buf + str_length - 1; if (((uint32_t)1 << radix_shift) == radix) { /* Power of two? */ - uint32_t *scan, *end; - printf("TODO: radix is a power of two\n"); - // TODO: -// int radix_mask = radix - 1, big_digit_len = 0, radix_digit; -// C_uword *scan, *end, big_digit = 0; -// -// scan = C_bignum_digits(bignum); -// end = scan + C_bignum_size(bignum); -// -// while (scan < end) { -// /* If radix isn't an exact divisor of digit length, handle overlap */ -// if (big_digit_len == 0) { -// big_digit = *scan++; -// big_digit_len = C_BIGNUM_DIGIT_LENGTH; -// } else { -// assert(index >= buf); -// radix_digit = big_digit; -// big_digit = *scan++; -// radix_digit |= ((unsigned int)big_digit << big_digit_len) & radix_mask; -// *index-- = characters[radix_digit]; -// big_digit >>= (radix_shift - big_digit_len); -// big_digit_len = C_BIGNUM_DIGIT_LENGTH - (radix_shift - big_digit_len); -// } -// -// while(big_digit_len >= radix_shift && index >= buf) { -// radix_digit = big_digit & radix_mask; -// *index-- = characters[radix_digit]; -// big_digit >>= radix_shift; -// big_digit_len -= radix_shift; -// } -// } -// -// assert(big_digit < radix); -// -// /* Final digit (like overlap at start of while loop) */ -// if (big_digit) *index-- = characters[big_digit]; -// -// if (negp) { -// /* Loop above might've overwritten sign position with a zero */ -// if (*(index+1) == '0') *(index+1) = '-'; -// else *index-- = '-'; -// } -// -// /* Length calculation is always precise for radix powers of two. */ -// assert(index == buf-1); + uint32_t *scan, *end, big_digit = 0; + int radix_mask = radix - 1, big_digit_len = 0, radix_digit; + + scan = C_bignum_digits(bn); + end = scan + bn->num_digits; + + while (scan < end) { + /* If radix isn't an exact divisor of digit length, handle overlap */ + if (big_digit_len == 0) { + big_digit = *scan++; + big_digit_len = C_BIGNUM_DIGIT_LENGTH; + } else { + assert(index >= buf); + radix_digit = big_digit; + big_digit = *scan++; + radix_digit |= ((unsigned int)big_digit << big_digit_len) & radix_mask; + *index-- = characters[radix_digit]; + big_digit >>= (radix_shift - big_digit_len); + big_digit_len = C_BIGNUM_DIGIT_LENGTH - (radix_shift - big_digit_len); + } + + while(big_digit_len >= radix_shift && index >= buf) { + radix_digit = big_digit & radix_mask; + *index-- = characters[radix_digit]; + big_digit >>= radix_shift; + big_digit_len -= radix_shift; + } + } + + assert(big_digit < radix); + + /* Final digit (like overlap at start of while loop) */ + if (big_digit) *index-- = characters[big_digit]; + + if (negp) { + /* Loop above might've overwritten sign position with a zero */ + if (*(index+1) == '0') *(index+1) = '-'; + else *index-- = '-'; + } + + /* Length calculation is always precise for radix powers of two. */ + assert(index == buf-1); } else { uint32_t base, *start, *scan, big_digit; int steps, i; - // TODO: make a working copy of the bignum so we can perform destructive operation below -// working_copy = allocate_tmp_bignum(C_fix(C_bignum_size(bignum)), -// C_mk_bool(negp), C_SCHEME_FALSE); -// bignum_digits_destructive_copy(working_copy, bignum); -// -//TODO: replace below two lines with this: start = C_bignum_digits(working_copy); - - start = &(bn->sign); // DEBUG ONLY - start += 1; // DEBUG ONLY - + bignum2_type *working_copy = gc_alloc_bignum2(data, bn->num_digits); + working_copy->sign = bn->sign; + bignum_digits_destructive_copy(working_copy, bn); + start = C_bignum_digits(working_copy); scan = start + bn->num_digits; /* Calculate the largest power of radix that fits a halfdigit: @@ -2582,7 +2571,7 @@ void bignum2string(void *data, object cont, bignum2_type *bn, int radix) } } assert(index >= buf-1); - // TODO: free_tmp_bignum(working_copy); + // FUTURE (?): free_tmp_bignum(working_copy); /* Move index onto first nonzero digit. We're writing a bignum here: it can't consist of only zeroes. */ diff --git a/test-bn.scm b/test-bn.scm index 5cc0241a..57420578 100644 --- a/test-bn.scm +++ b/test-bn.scm @@ -31,6 +31,10 @@ (test-bn -16326000 10) (test-bn #x0FFFffff 10) (test-bn #x0FFFffff 16) + (test-bn #x0eadbeef 16) + (test-bn #x0eadbeef 12) + (test-bn #x0eadbeef 8) + (test-bn #x0eadbeef 2) (test-bn #x3FFFffff 10) (test-larger-bn #x3FFF0000 #x0FFF0001 10) ))