Much investigation of bignum problems

bignum multiply is still not working, but as bignum read and bignum divide depend on it, it's the problem to hit first.
This commit is contained in:
Simon Brooke 2019-01-19 16:24:59 +00:00
parent 000ae3c392
commit 0f8bc990f2
9 changed files with 372 additions and 173 deletions

View file

@ -5,4 +5,4 @@
((= x 1) n) ((= x 1) n)
(t (* n (expt n (- x 1))))))) (t (* n (expt n (- x 1)))))))
(expt 2 65) (expt 2 60)

48
lisp/scratchpad.lisp Normal file
View file

@ -0,0 +1,48 @@
(set! i
(+
10000000000000000000
10000000000000000000
10000000000000000000
10000000000000000000
10000000000000000000
10000000000000000000
10000000000000000000
10000000000000000000
10000000000000000000
10000000000000000000))
(set! j (+ i i i i i i i i i i))
(set! k (+ j j j j j j j j j j))
(set! l (+ k k k k k k k k k k))
(set! m (+ l l l l l l l l l l))
(set! n (+ m m m m m m m m m m))
(set! o (+ n n n n n n n n n n))
(set! p (+ o o o o o o o o o o))
(set! q (+ p p p p p p p p p p))
(set! r (+ q q q q q q q q q q))
(set! s (+ r r r r r r r r r r))
(set! t (+ s s s s s s s s s s))
(set! u (+ t t t t t t t t t t))
(set! v (+ u u u u u u u u u u))
(set! x (+ v v v v v v v v v v))
(set! y (+ x x x x x x x x x x))
"we're OK to here: 10^36, which is below the 2^120 barrier so represented as two cells"
(inspect (set! z (+ y y y y y y y y y y)))
"This blows up: 10^37, which is a three cell bignum."
(inspect (+ z z z z z z z z z z))

84
lisp/scratchpad2.lisp Normal file
View file

@ -0,0 +1,84 @@
"This demonstrates that although the print representation of three cell bignums blows up, the internal representation is sane"
"We start by adding 8 copies of 2^60 - i.e. the first two-cell integer"
(set! a
(+
1152921504606846976
1152921504606846976
1152921504606846976
1152921504606846976
1152921504606846976
1152921504606846976
1152921504606846976
1152921504606846976))
"Then repeatedly add eight copies of the previous generation"
(set! b (+ a a a a a a a a))
(set! c (+ b b b b b b b b))
(set! d (+ c c c c c c c c))
(set! e (+ d d d d d d d d))
(set! f (+ e e e e e e e e))
(set! g (+ f f f f f f f f))
(set! h (+ g g g g g g g g))
(set! i (+ h h h h h h h h))
(set! j (+ i i i i i i i i))
(set! k (+ j j j j j j j j))
(set! l (+ k k k k k k k k))
(set! m (+ l l l l l l l l))
(set! n (+ m m m m m m m m))
(set! o (+ n n n n n n n n))
"p"
(set! p (+ o o o o o o o o))
"q"
(set! q (+ p p p p p p p p))
"r"
(set! r (+ q q q q q q q q))
"s"
(inspect
(set! s (+ r r r r r r r r)))
"t - first three cell integer. Printing blows up here"
(inspect
(set! t (+ s s s s s s s s)))
"u"
(inspect
(set! u (+ t t t t t t t t)))
"v"
(inspect
(set! v (+ u u u u u u u u)))
"w"
(inspect
(set! w (+ v v v v v v v v)))
(inspect
(set! x (+ w w w w w w w w)))
(inspect
(set! y (+ x x x x x x x x)))
(inspect
(set! z (+ y y y y y y y y)))
(inspect (+ z z z z z z z z))

View file

@ -36,7 +36,7 @@
/** /**
* hexadecimal digits for printing numbers. * hexadecimal digits for printing numbers.
*/ */
const char * hex_digits = "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
@ -95,6 +95,21 @@ struct cons_pointer make_integer( int64_t value, struct cons_pointer more ) {
} }
__int128_t cell_value( struct cons_pointer c, char op, bool is_first_cell ) {
long int val = nilp( c ) ? 0 : pointer2cell( c ).payload.integer.value;
long int carry = is_first_cell ? 0 : ( MAX_INTEGER + 1 );
__int128_t result = ( __int128_t ) integerp( c ) ?
( val == 0 ) ? carry : val : op == '*' ? 1 : 0;
debug_printf( DEBUG_ARITH,
L"cell_value: raw value is %ld, op = '%c', is_first_cell = %s; returning ",
val, op, is_first_cell ? "true" : "false" );
debug_print_128bit( result, DEBUG_ARITH );
debug_println( DEBUG_ARITH );
return result;
}
/** /**
* internal workings of both `add_integers` and `multiply_integers` (and * internal workings of both `add_integers` and `multiply_integers` (and
* possibly, later, other operations. Apply the operator `op` to the * possibly, later, other operations. Apply the operator `op` to the
@ -106,26 +121,22 @@ struct cons_pointer make_integer( int64_t value, struct cons_pointer more ) {
* up significantly WRONG, but the value in the more significant cell * up significantly WRONG, but the value in the more significant cell
* ends up correct. */ * ends up correct. */
struct cons_pointer operate_on_integers( struct cons_pointer a, struct cons_pointer operate_on_integers( struct cons_pointer a,
struct cons_pointer b, struct cons_pointer b, char op ) {
char op) {
struct cons_pointer result = NIL; struct cons_pointer result = NIL;
struct cons_pointer cursor = NIL; struct cons_pointer cursor = NIL;
__int128_t carry = 0; __int128_t carry = 0;
bool is_first_cell = true;
if ( integerp( a ) && integerp( b ) ) { if ( integerp( a ) && integerp( b ) ) {
debug_print( L"operate_on_integers: \n", DEBUG_ARITH ); debug_print( L"operate_on_integers: \n", DEBUG_ARITH );
debug_dump_object( a, DEBUG_ARITH ); debug_dump_object( a, DEBUG_ARITH );
debug_printf( DEBUG_ARITH, L" %c \n", op); debug_printf( DEBUG_ARITH, L" %c \n", op );
debug_dump_object( b, DEBUG_ARITH ); debug_dump_object( b, DEBUG_ARITH );
debug_println( DEBUG_ARITH ); debug_println( DEBUG_ARITH );
while ( !nilp( a ) || !nilp( b ) || carry != 0 ) { while ( !nilp( a ) || !nilp( b ) || carry != 0 ) {
__int128_t av = __int128_t av = cell_value( a, op, is_first_cell );
( __int128_t ) integerp( a ) ? pointer2cell( a ). __int128_t bv = cell_value( b, op, is_first_cell );
payload.integer.value : op == '*' ? 1 : 0;
__int128_t bv =
( __int128_t ) integerp( b ) ? pointer2cell( b ).
payload.integer.value : op == '*' ? 1 : 0;
/* slightly dodgy. `MAX_INTEGER` is substantially smaller than `LONG_MAX`, and /* slightly dodgy. `MAX_INTEGER` is substantially smaller than `LONG_MAX`, and
* `LONG_MAX * LONG_MAX` =~ the maximum value for `__int128_t`. So if the carry * `LONG_MAX * LONG_MAX` =~ the maximum value for `__int128_t`. So if the carry
@ -135,57 +146,59 @@ struct cons_pointer operate_on_integers( struct cons_pointer a,
*/ */
__int128_t rv = NAN; __int128_t rv = NAN;
switch (op) { switch ( op ) {
case '*': case '*':
rv = av * bv * ((carry == 0) ? 1 : 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_printf( DEBUG_ARITH,
debug_print_128bit( av, DEBUG_ARITH); L"operate_on_integers: op = '%c'; av = ", op );
debug_print( L"; bv = ", DEBUG_ARITH); debug_print_128bit( av, DEBUG_ARITH );
debug_print_128bit( bv, DEBUG_ARITH); debug_print( L"; bv = ", DEBUG_ARITH );
debug_print( L"; carry = ", DEBUG_ARITH); debug_print_128bit( bv, DEBUG_ARITH );
debug_print_128bit( carry, DEBUG_ARITH); debug_print( L"; carry = ", DEBUG_ARITH );
debug_print( L"; rv = ", DEBUG_ARITH); debug_print_128bit( carry, DEBUG_ARITH );
debug_print_128bit( rv, DEBUG_ARITH); debug_print( L"; rv = ", DEBUG_ARITH );
debug_print( L"\n", 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 {
// TODO: we're correctly detecting overflow, but not yet correctly // TODO: we're correctly detecting overflow, but not yet correctly
// handling it. // handling it.
carry = rv >> 60; carry = rv >> 60;
debug_printf( DEBUG_ARITH, debug_printf( DEBUG_ARITH,
L"operate_on_integers: 64 bit overflow; setting carry to %ld\n", L"operate_on_integers: 64 bit overflow; setting carry to %ld\n",
( int64_t ) carry ); ( int64_t ) carry );
rv &= MAX_INTEGER; rv &= MAX_INTEGER;
} }
struct cons_pointer tail = make_integer( ( int64_t ) rv, NIL ); struct cons_pointer tail = make_integer( ( int64_t ) rv, NIL );
if ( nilp( cursor ) ) { if ( nilp( cursor ) ) {
cursor = tail; cursor = tail;
} else { } else {
inc_ref( tail ); inc_ref( tail );
/* yes, this is a destructive change - but the integer has not yet been released /* yes, this is a destructive change - but the integer has not yet been released
* into the wild */ * into the wild */
struct cons_space_object *c = &pointer2cell( cursor ); struct cons_space_object *c = &pointer2cell( cursor );
c->payload.integer.more = tail; c->payload.integer.more = tail;
cursor = tail; cursor = tail;
} }
if ( nilp( result ) ) { if ( nilp( result ) ) {
result = cursor; result = cursor;
} }
a = pointer2cell( a ).payload.integer.more; a = pointer2cell( a ).payload.integer.more;
b = pointer2cell( b ).payload.integer.more; b = pointer2cell( b ).payload.integer.more;
is_first_cell = false;
} }
} }
@ -203,7 +216,7 @@ struct cons_pointer operate_on_integers( struct cons_pointer a,
struct cons_pointer add_integers( struct cons_pointer a, struct cons_pointer add_integers( struct cons_pointer a,
struct cons_pointer b ) { struct cons_pointer b ) {
return operate_on_integers(a, b, '+'); return operate_on_integers( a, b, '+' );
} }
/** /**
@ -212,7 +225,7 @@ struct cons_pointer add_integers( struct cons_pointer a,
*/ */
struct cons_pointer multiply_integers( struct cons_pointer a, struct cons_pointer multiply_integers( struct cons_pointer a,
struct cons_pointer b ) { struct cons_pointer b ) {
return operate_on_integers( a, b, '*'); return operate_on_integers( a, b, '*' );
} }
/** /**
@ -221,7 +234,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 = btowc(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 ) ) :
@ -239,6 +252,11 @@ struct cons_pointer integer_to_string_add_digit( int digit, int digits,
* when we get to the last digit from one integer cell, we have potentially * when we get to the last digit from one integer cell, we have potentially
* to be looking to the next. H'mmmm. * to be looking to the next. H'mmmm.
*/ */
/*
* TODO: this blows up when printing three-cell integers, but works fine
* for two-cell. What's happening is that when we cross the barrier we
* SHOULD print 2^120, but what we actually print is 2^117. H'mmm.
*/
struct cons_pointer integer_to_string( struct cons_pointer int_pointer, struct cons_pointer integer_to_string( struct cons_pointer int_pointer,
int base ) { int base ) {
struct cons_pointer result = NIL; struct cons_pointer result = NIL;
@ -253,24 +271,27 @@ struct cons_pointer integer_to_string( struct cons_pointer int_pointer,
while ( accumulator > 0 || !nilp( integer.payload.integer.more ) ) { while ( accumulator > 0 || !nilp( integer.payload.integer.more ) ) {
if ( !nilp( integer.payload.integer.more ) ) { if ( !nilp( integer.payload.integer.more ) ) {
integer = pointer2cell( integer.payload.integer.more ); integer = pointer2cell( integer.payload.integer.more );
accumulator += accumulator += integer.payload.integer.value == 0 ?
MAX_INTEGER :
( llabs( integer.payload.integer.value ) * ( llabs( integer.payload.integer.value ) *
( MAX_INTEGER + 1 ) ); ( MAX_INTEGER + 1 ) );
debug_print
( L"integer_to_string: crossing cell boundary, accumulator is: ",
DEBUG_IO );
debug_print_128bit( accumulator, DEBUG_IO );
debug_println( DEBUG_IO );
} }
debug_printf( DEBUG_IO,
L"integer_to_string: accumulator is %ld\n:",
accumulator );
do { do {
int offset = (int)(accumulator % base); 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, accumulator is: ",
offset, offset, hex_digits[offset] );
hex_digits[offset] ); debug_print_128bit( accumulator, DEBUG_IO );
debug_println( DEBUG_IO );
result = result =
integer_to_string_add_digit( offset, digits++, integer_to_string_add_digit( offset, digits++, result );
result );
accumulator = accumulator / base; accumulator = accumulator / base;
} while ( accumulator > base ); } while ( accumulator > base );
} }

View file

@ -42,7 +42,7 @@ 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); nilp( cell.payload.integer.more );
break; break;
case RATIOTV: case RATIOTV:
result = zerop( cell.payload.ratio.dividend ); result = zerop( cell.payload.ratio.dividend );

View file

@ -46,23 +46,24 @@ void debug_print( wchar_t *message, int level ) {
* stolen from https://stackoverflow.com/questions/11656241/how-to-print-uint128-t-number-using-gcc * stolen from https://stackoverflow.com/questions/11656241/how-to-print-uint128-t-number-using-gcc
*/ */
void debug_print_128bit( __int128_t n, int level ) { void debug_print_128bit( __int128_t n, int level ) {
#ifdef DEBUG #ifdef DEBUG
if ( level & verbosity ) { if ( level & verbosity ) {
if (n == 0) { if ( n == 0 ) {
fwprintf(stderr, L"0"); fwprintf( stderr, L"0" );
} else { } else {
char str[40] = {0}; // log10(1 << 128) + '\0' char str[40] = { 0 }; // log10(1 << 128) + '\0'
char *s = str + sizeof(str) - 1; // start at the end char *s = str + sizeof( str ) - 1; // start at the end
while (n != 0) { while ( n != 0 ) {
if (s == str) return; // never happens if ( s == str )
return; // never happens
*--s = "0123456789"[n % 10]; // save last digit *--s = "0123456789"[n % 10]; // save last digit
n /= 10; // drop it n /= 10; // drop it
} }
fwprintf(stderr, L"%s", s); fwprintf( stderr, L"%s", s );
}
} }
} #endif
#endif
} }
/** /**

View file

@ -157,104 +157,108 @@ struct cons_pointer read_continuation( struct stack_frame *frame,
* garbage is collected. * garbage is collected.
*/ */
struct cons_pointer read_number( struct stack_frame *frame, struct cons_pointer read_number( struct stack_frame *frame,
struct cons_pointer frame_pointer, struct cons_pointer frame_pointer,
FILE * input, FILE * input,
wint_t initial, bool seen_period ) { wint_t initial, bool seen_period ) {
debug_print( L"entering read_number\n", DEBUG_IO ); debug_print( L"entering read_number\n", DEBUG_IO );
struct cons_pointer result = make_integer( 0, NIL ); struct cons_pointer result = make_integer( 0, NIL );
/* TODO: we really need to be getting `base` from a privileged Lisp name - /* TODO: we really need to be getting `base` from a privileged Lisp name -
* and it should be the same privileged name we use when writing numbers */ * and it should be the same privileged name we use when writing numbers */
struct cons_pointer base = make_integer( 10, NIL ); struct cons_pointer base = make_integer( 10, NIL );
struct cons_pointer dividend = NIL; struct cons_pointer dividend = NIL;
int places_of_decimals = 0; int places_of_decimals = 0;
wint_t c; wint_t c;
bool neg = initial == btowc( '-' ); bool neg = initial == btowc( '-' );
if ( neg ) { if ( neg ) {
initial = fgetwc( input ); initial = fgetwc( input );
}
debug_printf( DEBUG_IO, L"read_number starting '%c' (%d)\n", initial,
initial );
for ( c = initial; iswdigit( c )
|| c == L'.' || c == L'/' || c == L','; c = fgetwc( input ) ) {
switch (c) {
case L'.':
if ( seen_period || !nilp( dividend ) ) {
return throw_exception( c_string_to_lisp_string
( L"Malformed number: too many periods" ),
frame_pointer );
} else {
debug_print(L"read_number: decimal point seen\n", DEBUG_IO);
seen_period = true;
}
break;
case L'/':
if ( seen_period || !nilp( dividend ) ) {
return throw_exception( c_string_to_lisp_string
( L"Malformed number: dividend of rational must be integer" ),
frame_pointer );
} else {
debug_print(L"read_number: ratio slash seen\n", DEBUG_IO);
dividend = result;
result = make_integer( 0, NIL );
}
break;
case L',' :
// silently ignore it.
break;
default:
result = add_integers( multiply_integers( result, base ),
make_integer( ( int ) c - ( int ) '0',
NIL ) );
debug_printf( DEBUG_IO,
L"read_number: added character %c, result now ", c );
debug_print_object( result, DEBUG_IO);
debug_print( L"\n", DEBUG_IO);
if ( seen_period ) {
places_of_decimals++;
}
} }
}
/* debug_printf( DEBUG_IO, L"read_number starting '%c' (%d)\n", initial,
initial );
for ( c = initial; iswdigit( c )
|| c == L'.' || c == L'/' || c == L','; c = fgetwc( input ) ) {
switch ( c ) {
case L'.':
if ( seen_period || !nilp( dividend ) ) {
return throw_exception( c_string_to_lisp_string
( L"Malformed number: too many periods" ),
frame_pointer );
} else {
debug_print( L"read_number: decimal point seen\n",
DEBUG_IO );
seen_period = true;
}
break;
case L'/':
if ( seen_period || !nilp( dividend ) ) {
return throw_exception( c_string_to_lisp_string
( L"Malformed number: dividend of rational must be integer" ),
frame_pointer );
} else {
debug_print( L"read_number: ratio slash seen\n",
DEBUG_IO );
dividend = result;
result = make_integer( 0, NIL );
}
break;
case L',':
// silently ignore it.
break;
default:
result = add_integers( multiply_integers( result, base ),
make_integer( ( int ) c - ( int ) '0',
NIL ) );
debug_printf( DEBUG_IO,
L"read_number: added character %c, result now ",
c );
debug_print_object( result, DEBUG_IO );
debug_print( L"\n", DEBUG_IO );
if ( seen_period ) {
places_of_decimals++;
}
}
}
/*
* 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); 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
( base ), ( base ),
places_of_decimals ), places_of_decimals ),
NIL ) ); NIL ) );
inc_ref( div ); inc_ref( div );
result = make_real( to_long_double( div ) ); result = make_real( to_long_double( div ) );
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); 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); debug_print( L"read_number: converting result to negative\n",
DEBUG_IO );
result = negative( frame_pointer, result ); result = negative( frame_pointer, result );
} }
debug_print( L"read_number returning\n", DEBUG_IO ); debug_print( L"read_number returning\n", DEBUG_IO );
debug_dump_object( result, DEBUG_IO ); debug_dump_object( result, DEBUG_IO );
return result; return result;
} }
/** /**

View file

@ -5,12 +5,12 @@
# (right on the boundary) # (right on the boundary)
a=1152921504606846975 a=1152921504606846975
b=1 b=1
expected='1152921504606846976' c=`echo "$a + $b" | bc`
output=`echo "(+ $a $b)" | target/psse -v 2 2>psse.log` expected='t'
output=`echo "(= (+ $a $b) $c)" | target/psse -v 2 2>psse.log`
actual=`echo $output |\ actual=`echo $output |\
tail -1 |\ tail -1`
sed 's/\,//g'`
echo -n "adding $a to $b: " echo -n "adding $a to $b: "
if [ "${expected}" = "${actual}" ] if [ "${expected}" = "${actual}" ]
@ -36,8 +36,9 @@ fi
# (just over the boundary) # (just over the boundary)
a='1152921504606846976' a='1152921504606846976'
b=1 b=1
expected='1152921504606846977' c=`echo "$a + $b" | bc`
output=`echo "(+ $a $b)" | target/psse -v 2 2>psse.log` expected='t'
output=`echo "(= (+ $a $b) $c)" | target/psse -v 2 2>psse.log`
actual=`echo $output |\ actual=`echo $output |\
tail -1 |\ tail -1 |\
@ -62,13 +63,15 @@ else
exit 1 exit 1
fi fi
##################################################################### #####################################################################
# add a bignum and a smallnum to produce a bignum # add a bignum and a smallnum to produce a bignum
# (just over the boundary) # (just over the boundary)
a='1152921504606846977' a='1152921504606846977'
b=1 b=1
expected='1152921504606846978' c=`echo "$a + $b" | bc`
output=`echo "(+ $a $b)" | target/psse -v 2 2>psse.log` expected='t'
output=`echo "(= (+ $a $b) $c)" | target/psse -v 2 2>psse.log`
actual=`echo $output |\ actual=`echo $output |\
tail -1 |\ tail -1 |\
@ -98,8 +101,9 @@ fi
# (just over the boundary) # (just over the boundary)
a=1 a=1
b=1152921504606846977 b=1152921504606846977
expected='1152921504606846978' c=`echo "$a + $b" | bc`
output=`echo "(+ $a $b)" | target/psse -v 2 2>psse.log` expected='t'
output=`echo "(= (+ $a $b) $c)" | target/psse -v 2 2>psse.log`
actual=`echo $output |\ actual=`echo $output |\
tail -1 |\ tail -1 |\
@ -124,12 +128,14 @@ else
exit 1 exit 1
fi fi
##################################################################### #####################################################################
# add two bignums to produce a bignum # add two bignums to produce a bignum
a=10000000000000000000 a=10000000000000000000
b=10000000000000000000 b=10000000000000000000
expected='20000000000000000000' c=`echo "$a + $b" | bc`
output=`echo "(+ $a $b)" | target/psse -v 2 2>psse.log` expected='t'
output=`echo "(= (+ $a $b) $c)" | target/psse -v 2 2>psse.log`
actual=`echo $output |\ actual=`echo $output |\
tail -1 |\ tail -1 |\
@ -154,13 +160,15 @@ else
exit 1 exit 1
fi fi
##################################################################### #####################################################################
# add a smallnum and a two-cell bignum to produce a three-cell bignum # add a smallnum and a two-cell bignum to produce a three-cell bignum
# (just over the boundary) # (just over the boundary)
a=1 a=1
b=1329227995784915872903807060280344576 b=1329227995784915872903807060280344576
expected='1329227995784915872903807060280344577' c=`echo "$a + $b" | bc`
output=`echo "(+ $a $b)" | target/psse -v 2 2>psse.log` expected='t'
output=`echo "(= (+ $a $b) $c)" | target/psse -v 2 2>psse.log`
actual=`echo $output |\ actual=`echo $output |\
tail -1 |\ tail -1 |\
@ -185,3 +193,36 @@ else
exit 1 exit 1
fi fi
#####################################################################
# This currently fails:
# (= (+ 1 3064991081731777716716694054300618367237478244367204352)
# 3064991081731777716716694054300618367237478244367204353)
a=1
b=3064991081731777716716694054300618367237478244367204352
c=`echo "$a + $b" | bc`
expected='t'
output=`echo "(= (+ $a $b) $c)" | target/psse -v 2 2>psse.log`
actual=`echo $output |\
tail -1 |\
sed 's/\,//g'`
echo -n "adding $a to $b: "
if [ "${expected}" = "${actual}" ]
then
echo "OK"
else
echo "Fail: expected '${expected}', got '${actual}'"
exit 1
fi
echo -n "checking a bignum was created: "
grep 'BIGNUM!' psse.log > /dev/null
if [ $? -eq "0" ]
then
echo "OK"
else
echo "Fail"
exit 1
fi

View file

@ -3,9 +3,9 @@
# Not really a unit test, but a check to see where bignum addition breaks # Not really a unit test, but a check to see where bignum addition breaks
broken=0 broken=0
i=1152921506900200000 i=11529215046068469750
# we've already proven we can successfullu get up to here # we've already proven we can successfullu get up to here
increment=10000 increment=1
while [ $broken -eq "0" ] while [ $broken -eq "0" ]
do do