Various refactorings around bignum arithmetic
This commit is contained in:
parent
d624c671cd
commit
7f93b04b72
|
@ -36,7 +36,7 @@
|
||||||
/**
|
/**
|
||||||
* hexadecimal digits for printing numbers.
|
* hexadecimal digits for printing numbers.
|
||||||
*/
|
*/
|
||||||
const wchar_t hex_digits[16] = L"0123456789ABCDEF";
|
const char * hex_digits = "0123456789ABCDEF";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Doctrine from here on in is that ALL integers are bignums, it's just
|
* Doctrine from here on in is that ALL integers are bignums, it's just
|
||||||
|
@ -133,13 +133,24 @@ struct cons_pointer operate_on_integers( struct cons_pointer a,
|
||||||
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case '*':
|
case '*':
|
||||||
rv = ( av * bv ) + carry;
|
rv = av * bv * ((carry == 0) ? 1 : carry);
|
||||||
break;
|
break;
|
||||||
case '+':
|
case '+':
|
||||||
rv = av + bv + carry;
|
rv = av + bv + carry;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug_printf( DEBUG_ARITH, L"operate_on_integers: op = '%c'; av = ", op);
|
||||||
|
debug_print_128bit( av, DEBUG_ARITH);
|
||||||
|
debug_print( L"; bv = ", DEBUG_ARITH);
|
||||||
|
debug_print_128bit( bv, DEBUG_ARITH);
|
||||||
|
debug_print( L"; carry = ", DEBUG_ARITH);
|
||||||
|
debug_print_128bit( carry, DEBUG_ARITH);
|
||||||
|
debug_print( L"; rv = ", DEBUG_ARITH);
|
||||||
|
debug_print_128bit( rv, DEBUG_ARITH);
|
||||||
|
debug_print( L"\n", DEBUG_ARITH);
|
||||||
|
|
||||||
|
|
||||||
if ( MAX_INTEGER >= rv ) {
|
if ( MAX_INTEGER >= rv ) {
|
||||||
carry = 0;
|
carry = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -206,7 +217,7 @@ struct cons_pointer multiply_integers( struct cons_pointer a,
|
||||||
struct cons_pointer integer_to_string_add_digit( int digit, int digits,
|
struct cons_pointer integer_to_string_add_digit( int digit, int digits,
|
||||||
struct cons_pointer tail ) {
|
struct cons_pointer tail ) {
|
||||||
digits++;
|
digits++;
|
||||||
wint_t character = ( wint_t ) hex_digits[digit];
|
wint_t character = btowc(hex_digits[digit]);
|
||||||
return ( digits % 3 == 0 ) ?
|
return ( digits % 3 == 0 ) ?
|
||||||
make_string( L',', make_string( character,
|
make_string( L',', make_string( character,
|
||||||
tail ) ) :
|
tail ) ) :
|
||||||
|
@ -247,13 +258,14 @@ struct cons_pointer integer_to_string( struct cons_pointer int_pointer,
|
||||||
L"integer_to_string: accumulator is %ld\n:",
|
L"integer_to_string: accumulator is %ld\n:",
|
||||||
accumulator );
|
accumulator );
|
||||||
do {
|
do {
|
||||||
|
int offset = (int)(accumulator % base);
|
||||||
debug_printf( DEBUG_IO,
|
debug_printf( DEBUG_IO,
|
||||||
L"integer_to_string: digit is %ld, hexadecimal is %C\n:",
|
L"integer_to_string: digit is %ld, hexadecimal is %c\n:",
|
||||||
accumulator % base,
|
offset,
|
||||||
btowc(hex_digits[accumulator % base] ));
|
hex_digits[offset] );
|
||||||
|
|
||||||
result =
|
result =
|
||||||
integer_to_string_add_digit( accumulator % base, digits++,
|
integer_to_string_add_digit( offset, digits++,
|
||||||
result );
|
result );
|
||||||
accumulator = accumulator / base;
|
accumulator = accumulator / base;
|
||||||
} while ( accumulator > base );
|
} while ( accumulator > base );
|
||||||
|
|
|
@ -41,7 +41,8 @@ bool zerop( struct cons_pointer arg ) {
|
||||||
|
|
||||||
switch ( cell.tag.value ) {
|
switch ( cell.tag.value ) {
|
||||||
case INTEGERTV:
|
case INTEGERTV:
|
||||||
result = cell.payload.integer.value == 0;
|
result = cell.payload.integer.value == 0 &&
|
||||||
|
nilp(cell.payload.integer.more);
|
||||||
break;
|
break;
|
||||||
case RATIOTV:
|
case RATIOTV:
|
||||||
result = zerop( cell.payload.ratio.dividend );
|
result = zerop( cell.payload.ratio.dividend );
|
||||||
|
@ -134,9 +135,9 @@ struct cons_pointer add_2( struct stack_frame *frame,
|
||||||
struct cons_space_object cell2 = pointer2cell( arg2 );
|
struct cons_space_object cell2 = pointer2cell( arg2 );
|
||||||
|
|
||||||
debug_print( L"add_2( arg1 = ", DEBUG_ARITH );
|
debug_print( L"add_2( arg1 = ", DEBUG_ARITH );
|
||||||
debug_print_object( arg1, DEBUG_ARITH );
|
debug_dump_object( arg1, DEBUG_ARITH );
|
||||||
debug_print( L"; arg2 = ", DEBUG_ARITH );
|
debug_print( L"; arg2 = ", DEBUG_ARITH );
|
||||||
debug_print_object( arg2, DEBUG_ARITH );
|
debug_dump_object( arg2, DEBUG_ARITH );
|
||||||
debug_print( L"\n", DEBUG_ARITH );
|
debug_print( L"\n", DEBUG_ARITH );
|
||||||
|
|
||||||
if ( zerop( arg1 ) ) {
|
if ( zerop( arg1 ) ) {
|
||||||
|
|
23
src/debug.c
23
src/debug.c
|
@ -42,6 +42,29 @@ void debug_print( wchar_t *message, int level ) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stolen from https://stackoverflow.com/questions/11656241/how-to-print-uint128-t-number-using-gcc
|
||||||
|
*/
|
||||||
|
void debug_print_128bit( __int128_t n, int level ) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
if ( level & verbosity ) {
|
||||||
|
if (n == 0) {
|
||||||
|
fwprintf(stderr, L"0");
|
||||||
|
} else {
|
||||||
|
char str[40] = {0}; // log10(1 << 128) + '\0'
|
||||||
|
char *s = str + sizeof(str) - 1; // start at the end
|
||||||
|
while (n != 0) {
|
||||||
|
if (s == str) return; // never happens
|
||||||
|
|
||||||
|
*--s = "0123456789"[n % 10]; // save last digit
|
||||||
|
n /= 10; // drop it
|
||||||
|
}
|
||||||
|
fwprintf(stderr, L"%s", s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* print a line feed to stderr, if `verbosity` matches `level`.
|
* print a line feed to stderr, if `verbosity` matches `level`.
|
||||||
* `verbosity is a set of flags, see debug_print.h; so you can
|
* `verbosity is a set of flags, see debug_print.h; so you can
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
extern int verbosity;
|
extern int verbosity;
|
||||||
|
|
||||||
void debug_print( wchar_t *message, int level );
|
void debug_print( wchar_t *message, int level );
|
||||||
|
void debug_print_128bit( __int128_t n, int level );
|
||||||
void debug_println( int level );
|
void debug_println( int level );
|
||||||
void debug_printf( int level, wchar_t *format, ... );
|
void debug_printf( int level, wchar_t *format, ... );
|
||||||
void debug_print_object( struct cons_pointer pointer, int level );
|
void debug_print_object( struct cons_pointer pointer, int level );
|
||||||
|
|
|
@ -1133,7 +1133,6 @@ struct cons_pointer lisp_source( struct stack_frame *frame,
|
||||||
struct cons_pointer lisp_inspect( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
struct cons_pointer lisp_inspect( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
||||||
struct cons_pointer env ) {
|
struct cons_pointer env ) {
|
||||||
debug_print( L"Entering print\n", DEBUG_IO );
|
debug_print( L"Entering print\n", DEBUG_IO );
|
||||||
struct cons_pointer result = frame->arg[0];
|
|
||||||
FILE *output = stdout;
|
FILE *output = stdout;
|
||||||
struct cons_pointer out_stream = writep( frame->arg[1] ) ?
|
struct cons_pointer out_stream = writep( frame->arg[1] ) ?
|
||||||
frame->arg[1] : get_default_stream( false, env );
|
frame->arg[1] : get_default_stream( false, env );
|
||||||
|
@ -1150,5 +1149,5 @@ struct cons_pointer lisp_inspect( struct stack_frame *frame, struct cons_pointer
|
||||||
dec_ref( out_stream );
|
dec_ref( out_stream );
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return frame->arg[0];
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,33 +180,41 @@ struct cons_pointer read_number( struct stack_frame *frame,
|
||||||
|
|
||||||
for ( c = initial; iswdigit( c )
|
for ( c = initial; iswdigit( c )
|
||||||
|| c == L'.' || c == L'/' || c == L','; c = fgetwc( input ) ) {
|
|| c == L'.' || c == L'/' || c == L','; c = fgetwc( input ) ) {
|
||||||
if ( c == btowc( '.' ) ) {
|
switch (c) {
|
||||||
|
case L'.':
|
||||||
if ( seen_period || !nilp( dividend ) ) {
|
if ( seen_period || !nilp( dividend ) ) {
|
||||||
return throw_exception( c_string_to_lisp_string
|
return throw_exception( c_string_to_lisp_string
|
||||||
( L"Malformed number: too many periods" ),
|
( L"Malformed number: too many periods" ),
|
||||||
frame_pointer );
|
frame_pointer );
|
||||||
} else {
|
} else {
|
||||||
|
debug_print(L"read_number: decimal point seen\n", DEBUG_IO);
|
||||||
seen_period = true;
|
seen_period = true;
|
||||||
}
|
}
|
||||||
} else if ( c == btowc( '/' ) ) {
|
break;
|
||||||
|
case L'/':
|
||||||
if ( seen_period || !nilp( dividend ) ) {
|
if ( seen_period || !nilp( dividend ) ) {
|
||||||
return throw_exception( c_string_to_lisp_string
|
return throw_exception( c_string_to_lisp_string
|
||||||
( L"Malformed number: dividend of rational must be integer" ),
|
( L"Malformed number: dividend of rational must be integer" ),
|
||||||
frame_pointer );
|
frame_pointer );
|
||||||
} else {
|
} else {
|
||||||
|
debug_print(L"read_number: ratio slash seen\n", DEBUG_IO);
|
||||||
dividend = result;
|
dividend = result;
|
||||||
|
|
||||||
result = make_integer( 0, NIL );
|
result = make_integer( 0, NIL );
|
||||||
}
|
}
|
||||||
} else if ( c == L',' ) {
|
break;
|
||||||
|
case L',' :
|
||||||
// silently ignore it.
|
// silently ignore it.
|
||||||
} else {
|
break;
|
||||||
|
default:
|
||||||
result = add_integers( multiply_integers( result, base ),
|
result = add_integers( multiply_integers( result, base ),
|
||||||
make_integer( ( int ) c - ( int ) '0',
|
make_integer( ( int ) c - ( int ) '0',
|
||||||
NIL ) );
|
NIL ) );
|
||||||
|
|
||||||
debug_printf( DEBUG_IO,
|
debug_printf( DEBUG_IO,
|
||||||
L"Added character %c, result now %ld\n", c, result );
|
L"read_number: added character %c, result now ", c );
|
||||||
|
debug_print_object( result, DEBUG_IO);
|
||||||
|
debug_print( L"\n", DEBUG_IO);
|
||||||
|
|
||||||
if ( seen_period ) {
|
if ( seen_period ) {
|
||||||
places_of_decimals++;
|
places_of_decimals++;
|
||||||
|
@ -218,7 +226,9 @@ struct cons_pointer read_number( struct stack_frame *frame,
|
||||||
* push back the character read which was not a digit
|
* push back the character read which was not a digit
|
||||||
*/
|
*/
|
||||||
ungetwc( c, input );
|
ungetwc( c, input );
|
||||||
|
|
||||||
if ( seen_period ) {
|
if ( seen_period ) {
|
||||||
|
debug_print(L"read_number: converting result to real\n", DEBUG_IO);
|
||||||
struct cons_pointer div = make_ratio( frame_pointer, result,
|
struct cons_pointer div = make_ratio( frame_pointer, result,
|
||||||
make_integer( powl
|
make_integer( powl
|
||||||
( to_long_double
|
( to_long_double
|
||||||
|
@ -231,10 +241,13 @@ struct cons_pointer read_number( struct stack_frame *frame,
|
||||||
|
|
||||||
dec_ref( div );
|
dec_ref( div );
|
||||||
} else if ( integerp( dividend ) ) {
|
} else if ( integerp( dividend ) ) {
|
||||||
|
debug_print(L"read_number: converting result to ratio\n", DEBUG_IO);
|
||||||
result = make_ratio( frame_pointer, dividend, result );
|
result = make_ratio( frame_pointer, dividend, result );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( neg ) {
|
if ( neg ) {
|
||||||
|
debug_print(L"read_number: converting result to negative\n", DEBUG_IO);
|
||||||
|
|
||||||
result = negative( frame_pointer, result );
|
result = negative( frame_pointer, result );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue