Now creating the correct internal bignum representation
add_integers returns an integer which by inspection of the internal representation is correct, but the print representation is not correct.
This commit is contained in:
parent
4295b6e57f
commit
d9d789fdd0
|
@ -4,3 +4,5 @@
|
||||||
(cond
|
(cond
|
||||||
((= x 1) n)
|
((= x 1) n)
|
||||||
(t (* n (expt n (- x 1)))))))
|
(t (* n (expt n (- x 1)))))))
|
||||||
|
|
||||||
|
(expt 2 65)
|
||||||
|
|
|
@ -2,6 +2,6 @@
|
||||||
|
|
||||||
Each integer comprises at least one cell of type INTR, holding a signed 64 bit integer with a value in the range 0 ... MAX-INTEGER, where the actual value of MAX-INTEGER does not need to be the same as the C language LONG\_MAX, provided that it is less than this. It seems to me that a convenient number would be the largest number less than LONG\_MAX which has all bits set
|
Each integer comprises at least one cell of type INTR, holding a signed 64 bit integer with a value in the range 0 ... MAX-INTEGER, where the actual value of MAX-INTEGER does not need to be the same as the C language LONG\_MAX, provided that it is less than this. It seems to me that a convenient number would be the largest number less than LONG\_MAX which has all bits set
|
||||||
|
|
||||||
LONG\_MAX is 0x7FFFFFFFFFFFFFFF, so the number we're looking for is 0xFFFFFFFFFFFFFFF, which is 1,152,921,504,606,846,975, which is 2^60 - 1. This means we can use bit masking with 0xFFFFFFFFFFFFFFF to extract the part of **int64_t** which will fit in a single cell.
|
LONG\_MAX is 0x7FFFFFFFFFFFFFFF, so the number we're looking for is 0x0FFFFFFFFFFFFFFF, which is 1,152,921,504,606,846,975, which is 2^60 - 1. This means we can use bit masking with 0xFFFFFFFFFFFFFFF to extract the part of **int64_t** which will fit in a single cell.
|
||||||
|
|
||||||
It also means that if we multiply two **int64_t**s into an **__int128_t**, we can then right-shift by 60 places to get the carry.
|
It also means that if we multiply two **int64_t**s into an **__int128_t**, we can then right-shift by 60 places to get the carry.
|
|
@ -31,7 +31,7 @@
|
||||||
/*
|
/*
|
||||||
* The maximum value we will allow in an integer cell.
|
* The maximum value we will allow in an integer cell.
|
||||||
*/
|
*/
|
||||||
#define MAX_INTEGER ((__int128_t)0xFFFFFFFFFFFFFFF)
|
#define MAX_INTEGER ((__int128_t)0x0fffffffffffffffL)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hexadecimal digits for printing numbers.
|
* hexadecimal digits for printing numbers.
|
||||||
|
@ -109,9 +109,9 @@ struct cons_pointer add_integers( struct cons_pointer a,
|
||||||
if ( integerp( a ) && integerp( b ) ) {
|
if ( integerp( a ) && integerp( b ) ) {
|
||||||
debug_print( L"add_integers: ", DEBUG_ARITH );
|
debug_print( L"add_integers: ", DEBUG_ARITH );
|
||||||
debug_print_object( a, DEBUG_ARITH );
|
debug_print_object( a, DEBUG_ARITH );
|
||||||
debug_print( L" x ", DEBUG_ARITH );
|
debug_print( L" + ", DEBUG_ARITH );
|
||||||
debug_print_object( b, DEBUG_ARITH );
|
debug_print_object( b, DEBUG_ARITH );
|
||||||
debug_printf( DEBUG_ARITH, L"; carry = %ld\n", carry );
|
debug_println( DEBUG_ARITH);
|
||||||
|
|
||||||
while ( !nilp( a ) || !nilp( b ) || carry != 0 ) {
|
while ( !nilp( a ) || !nilp( b ) || carry != 0 ) {
|
||||||
__int128_t av =
|
__int128_t av =
|
||||||
|
@ -133,7 +133,7 @@ struct cons_pointer add_integers( struct cons_pointer a,
|
||||||
rv = rv & MAX_INTEGER;
|
rv = rv & MAX_INTEGER;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cons_pointer tail = make_integer( (int64_t)(rv << 64), NIL);
|
struct cons_pointer tail = make_integer( (int64_t)rv, NIL);
|
||||||
|
|
||||||
if (nilp(cursor)) {
|
if (nilp(cursor)) {
|
||||||
cursor = tail;
|
cursor = tail;
|
||||||
|
@ -145,12 +145,16 @@ struct cons_pointer add_integers( struct cons_pointer a,
|
||||||
c->payload.integer.more = tail;
|
c->payload.integer.more = tail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( nilp(result) ) {
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debug_print( L"add_integers returning: ", DEBUG_ARITH );
|
debug_print( L"add_integers returning: ", DEBUG_ARITH );
|
||||||
debug_print_object( result, DEBUG_ARITH );
|
debug_dump_object( result, DEBUG_ARITH );
|
||||||
debug_println( DEBUG_ARITH );
|
debug_println( DEBUG_ARITH );
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -167,10 +171,10 @@ struct cons_pointer multiply_integers( struct cons_pointer a,
|
||||||
__int128_t carry = 0;
|
__int128_t carry = 0;
|
||||||
|
|
||||||
if ( integerp( a ) && integerp( b ) ) {
|
if ( integerp( a ) && integerp( b ) ) {
|
||||||
debug_print( L"multiply_integers: ", DEBUG_ARITH );
|
debug_print( L"multiply_integers: \n", DEBUG_ARITH );
|
||||||
debug_print_object( a, DEBUG_ARITH );
|
debug_dump_object( a, DEBUG_ARITH );
|
||||||
debug_print( L" x ", DEBUG_ARITH );
|
debug_print( L" x \n", DEBUG_ARITH );
|
||||||
debug_print_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 ) {
|
||||||
|
@ -196,10 +200,10 @@ struct cons_pointer multiply_integers( struct cons_pointer a,
|
||||||
debug_printf( DEBUG_ARITH,
|
debug_printf( DEBUG_ARITH,
|
||||||
L"multiply_integers: 64 bit overflow; setting carry to %ld\n",
|
L"multiply_integers: 64 bit overflow; setting carry to %ld\n",
|
||||||
(int64_t)carry );
|
(int64_t)carry );
|
||||||
rv = rv & MAX_INTEGER;
|
rv &= MAX_INTEGER; // <<< PROBLEM IS HERE!
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cons_pointer tail = make_integer( (int64_t)(rv << 64), NIL);
|
struct cons_pointer tail = make_integer( (int64_t)rv, NIL);
|
||||||
|
|
||||||
if (nilp(cursor)) {
|
if (nilp(cursor)) {
|
||||||
cursor = tail;
|
cursor = tail;
|
||||||
|
@ -220,8 +224,8 @@ struct cons_pointer multiply_integers( struct cons_pointer a,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_print( L"multiply_integers returning: ", DEBUG_ARITH );
|
debug_print( L"multiply_integers returning:\n", DEBUG_ARITH );
|
||||||
debug_print_object( result, DEBUG_ARITH );
|
debug_dump_object( result, DEBUG_ARITH );
|
||||||
debug_println( DEBUG_ARITH );
|
debug_println( DEBUG_ARITH );
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -260,7 +264,11 @@ struct cons_pointer integer_to_string( struct cons_pointer int_pointer,
|
||||||
accumulator = llabs( accumulator );
|
accumulator = llabs( accumulator );
|
||||||
int digits = 0;
|
int digits = 0;
|
||||||
|
|
||||||
if ( accumulator == 0 ) {
|
if ( accumulator == 0 && !nilp(integer.payload.integer.more) ) {
|
||||||
|
accumulator = MAX_INTEGER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( accumulator == 0) {
|
||||||
result = c_string_to_lisp_string( L"0" );
|
result = c_string_to_lisp_string( L"0" );
|
||||||
} else {
|
} else {
|
||||||
while ( accumulator > 0 ) {
|
while ( accumulator > 0 ) {
|
||||||
|
|
|
@ -161,6 +161,9 @@ struct cons_pointer read_number( struct stack_frame *frame,
|
||||||
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 = NIL;
|
struct cons_pointer result = NIL;
|
||||||
|
|
||||||
|
/* TODO: accumulator and dividend cannot be `int64_t`s, otherwise we cannot
|
||||||
|
* read bignums. They will have to be Lisp integers. */
|
||||||
int64_t accumulator = 0;
|
int64_t accumulator = 0;
|
||||||
int64_t dividend = 0;
|
int64_t dividend = 0;
|
||||||
int places_of_decimals = 0;
|
int places_of_decimals = 0;
|
||||||
|
|
14
unit-tests/bignum.sh
Normal file
14
unit-tests/bignum.sh
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
expected='1,152,921,504,606,846,976'
|
||||||
|
# 1,152,921,504,606,846,975 is the largest single cell positive integer;
|
||||||
|
# consequently 1,152,921,504,606,846,976 is the first two cell positive integer.
|
||||||
|
actual=`echo '(+ 1,152,921,504,606,846,975 1)' | target/psse -v 68 2>bignum.log | tail -1`
|
||||||
|
|
||||||
|
if [ "${expected}" = "${actual}" ]
|
||||||
|
then
|
||||||
|
echo "OK"
|
||||||
|
else
|
||||||
|
echo "Fail: expected '${expected}', got '${actual}'"
|
||||||
|
exit 1
|
||||||
|
fi
|
Loading…
Reference in a new issue