Printing of bignums basically done, not tested.
This commit is contained in:
parent
342f0308d3
commit
489f008044
14 changed files with 244 additions and 164 deletions
|
|
@ -12,116 +12,182 @@
|
|||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
/*
|
||||
* wide characters
|
||||
*/
|
||||
#include <wchar.h>
|
||||
#include <wctype.h>
|
||||
|
||||
#include "conspage.h"
|
||||
#include "consspaceobject.h"
|
||||
#include "debug.h"
|
||||
|
||||
/**
|
||||
* hexadecimal digits for printing numbers.
|
||||
*/
|
||||
const wchar_t *hex_digits = L"0123456789ABCDEF";
|
||||
|
||||
/*
|
||||
* Doctrine from here on in is that ALL integers are bignums, it's just
|
||||
* that integers less than 65 bits are bignums of one cell only.
|
||||
*
|
||||
* TODO: I have no idea at all how I'm going to print bignums!
|
||||
*/
|
||||
|
||||
/**
|
||||
* return the numeric value of this cell, as a C primitive double, not
|
||||
* as a cons-space object. Cell may in principle be any kind of number.
|
||||
*/
|
||||
long double numeric_value( struct cons_pointer pointer ) {
|
||||
long double result = NAN;
|
||||
struct cons_space_object *cell = &pointer2cell( pointer );
|
||||
long double result = NAN;
|
||||
struct cons_space_object *cell = &pointer2cell( pointer );
|
||||
|
||||
switch (cell->tag.value) {
|
||||
case INTEGERTV:
|
||||
result = 1.0;
|
||||
while (cell->tag.value == INTEGERTV) {
|
||||
result = (result * LONG_MAX * cell->payload.integer.value);
|
||||
cell = &pointer2cell(cell->payload.integer.more);
|
||||
switch ( cell->tag.value ) {
|
||||
case INTEGERTV:
|
||||
result = 1.0;
|
||||
while ( cell->tag.value == INTEGERTV ) {
|
||||
result = ( result * LONG_MAX * cell->payload.integer.value );
|
||||
cell = &pointer2cell( cell->payload.integer.more );
|
||||
}
|
||||
break;
|
||||
case RATIOTV:
|
||||
result = numeric_value( cell->payload.ratio.dividend ) /
|
||||
numeric_value( cell->payload.ratio.divisor );
|
||||
break;
|
||||
case REALTV:
|
||||
result = cell->payload.real.value;
|
||||
break;
|
||||
// default is NAN
|
||||
}
|
||||
break;
|
||||
case RATIOTV:
|
||||
result = numeric_value(cell->payload.ratio.dividend) /
|
||||
numeric_value(cell->payload.ratio.divisor);
|
||||
break;
|
||||
case REALTV:
|
||||
result = cell->payload.real.value;
|
||||
break;
|
||||
// default is NAN
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate an integer cell representing this value and return a cons pointer to it.
|
||||
*/
|
||||
struct cons_pointer make_integer( int64_t value, struct cons_pointer more ) {
|
||||
struct cons_pointer result = NIL;
|
||||
struct cons_pointer result = NIL;
|
||||
|
||||
if (integerp(more) || nilp(more)) {
|
||||
result = allocate_cell( INTEGERTAG );
|
||||
struct cons_space_object *cell = &pointer2cell( result );
|
||||
cell->payload.integer.value = value;
|
||||
cell->payload.integer.more = more;
|
||||
if ( integerp( more ) || nilp( more ) ) {
|
||||
result = allocate_cell( INTEGERTAG );
|
||||
struct cons_space_object *cell = &pointer2cell( result );
|
||||
cell->payload.integer.value = value;
|
||||
cell->payload.integer.more = more;
|
||||
|
||||
debug_dump_object( result, DEBUG_ARITH );
|
||||
}
|
||||
debug_dump_object( result, DEBUG_ARITH );
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the sum of the integers pointed to by `a` and `b`. If either isn't
|
||||
* an integer, will return nil.
|
||||
*/
|
||||
struct cons_pointer add_integers( struct cons_pointer a, struct cons_pointer b) {
|
||||
struct cons_pointer result = NIL;
|
||||
int64_t carry = 0;
|
||||
struct cons_pointer add_integers( struct cons_pointer a,
|
||||
struct cons_pointer b ) {
|
||||
struct cons_pointer result = NIL;
|
||||
int64_t carry = 0;
|
||||
|
||||
if (integerp(a) && integerp(b)) {
|
||||
while (!nilp(a) || !nilp(b) || carry != 0) {
|
||||
int64_t av = integerp(a) ? pointer2cell(a).payload.integer.value : 0;
|
||||
int64_t bv = integerp(b) ? pointer2cell(b).payload.integer.value : 0;
|
||||
if ( integerp( a ) && integerp( b ) ) {
|
||||
while ( !nilp( a ) || !nilp( b ) || carry != 0 ) {
|
||||
int64_t av =
|
||||
integerp( a ) ? pointer2cell( a ).payload.integer.value : 0;
|
||||
int64_t bv =
|
||||
integerp( b ) ? pointer2cell( b ).payload.integer.value : 0;
|
||||
|
||||
__int128_t rv = av + bv + carry;
|
||||
__int128_t rv = av + bv + carry;
|
||||
|
||||
if (rv > LONG_MAX || rv < LONG_MIN) {
|
||||
carry = llabs(rv / LONG_MAX);
|
||||
rv = rv % LONG_MAX;
|
||||
} else {
|
||||
carry = 0;
|
||||
}
|
||||
if ( rv > LONG_MAX || rv < LONG_MIN ) {
|
||||
carry = llabs( rv / LONG_MAX );
|
||||
rv = rv % LONG_MAX;
|
||||
} else {
|
||||
carry = 0;
|
||||
}
|
||||
|
||||
result = make_integer( rv, result);
|
||||
a = pointer2cell(a).payload.integer.more;
|
||||
b = pointer2cell(b).payload.integer.more;
|
||||
result = make_integer( rv, result );
|
||||
a = pointer2cell( a ).payload.integer.more;
|
||||
b = pointer2cell( b ).payload.integer.more;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the product of the integers pointed to by `a` and `b`. If either isn't
|
||||
* an integer, will return nil.
|
||||
*/
|
||||
struct cons_pointer multiply_integers( struct cons_pointer a, struct cons_pointer b) {
|
||||
struct cons_pointer result = NIL;
|
||||
int64_t carry = 0;
|
||||
struct cons_pointer multiply_integers( struct cons_pointer a,
|
||||
struct cons_pointer b ) {
|
||||
struct cons_pointer result = NIL;
|
||||
int64_t carry = 0;
|
||||
|
||||
if (integerp(a) && integerp(b)) {
|
||||
while (!nilp(a) || ! nilp(b) || carry != 0) {
|
||||
int64_t av = integerp(a) ? pointer2cell(a).payload.integer.value : 1;
|
||||
int64_t bv = integerp(b) ? pointer2cell(b).payload.integer.value : 1;
|
||||
if ( integerp( a ) && integerp( b ) ) {
|
||||
while ( !nilp( a ) || !nilp( b ) || carry != 0 ) {
|
||||
int64_t av =
|
||||
integerp( a ) ? pointer2cell( a ).payload.integer.value : 1;
|
||||
int64_t bv =
|
||||
integerp( b ) ? pointer2cell( b ).payload.integer.value : 1;
|
||||
|
||||
__int128_t rv = (av * bv) + carry;
|
||||
__int128_t rv = ( av * bv ) + carry;
|
||||
|
||||
if (rv > LONG_MAX || rv < LONG_MIN) {
|
||||
carry = llabs(rv / LONG_MAX);
|
||||
rv = rv % LONG_MAX;
|
||||
} else {
|
||||
carry = 0;
|
||||
}
|
||||
if ( rv > LONG_MAX || rv < LONG_MIN ) {
|
||||
carry = llabs( rv / LONG_MAX );
|
||||
rv = rv % LONG_MAX;
|
||||
} else {
|
||||
carry = 0;
|
||||
}
|
||||
|
||||
result = make_integer( rv, result);
|
||||
a = pointer2cell(a).payload.integer.more;
|
||||
b = pointer2cell(b).payload.integer.more;
|
||||
result = make_integer( rv, result );
|
||||
a = pointer2cell( a ).payload.integer.more;
|
||||
b = pointer2cell( b ).payload.integer.more;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* The general principle of printing a bignum is that you print the least
|
||||
* significant digit in whatever base you're dealing with, divide through
|
||||
* by the base, print the next, and carry on until you've none left.
|
||||
* Obviously, that means you print from right to left. Given that we build
|
||||
* strings from right to left, 'printing' an integer to a lisp string
|
||||
* would seem reasonably easy. The problem is when you jump from one integer
|
||||
* object to the next. 64 bit integers don't align with decimal numbers, so
|
||||
* when we get to the last digit from one integer cell, we have potentially
|
||||
* to be looking to the next. H'mmmm.
|
||||
*/
|
||||
struct cons_pointer integer_to_string( struct cons_pointer int_pointer,
|
||||
int base ) {
|
||||
struct cons_pointer result = NIL;
|
||||
struct cons_space_object integer = pointer2cell( int_pointer );
|
||||
int64_t accumulator = integer.payload.integer.value;
|
||||
bool is_negative = accumulator < 0;
|
||||
accumulator = llabs( accumulator );
|
||||
|
||||
while ( accumulator > 0 ) {
|
||||
while ( accumulator > base ) {
|
||||
result = make_string( hex_digits[accumulator % base], result );
|
||||
accumulator = accumulator / base;
|
||||
}
|
||||
|
||||
if ( integerp( integer.payload.integer.more ) ) {
|
||||
integer = pointer2cell( integer.payload.integer.more );
|
||||
int64_t i = integer.payload.integer.value;
|
||||
|
||||
/* TODO: I don't believe it's as simple as this! */
|
||||
accumulator += ( base * ( i % base ) );
|
||||
result = make_string( hex_digits[accumulator % base], result );
|
||||
accumulator += ( base * ( i / base ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_negative ) {
|
||||
result = make_string( L'-', result );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,13 @@ long double numeric_value( struct cons_pointer pointer );
|
|||
*/
|
||||
struct cons_pointer make_integer( int64_t value, struct cons_pointer more );
|
||||
|
||||
struct cons_pointer add_integers( struct cons_pointer a, struct cons_pointer b);
|
||||
struct cons_pointer add_integers( struct cons_pointer a,
|
||||
struct cons_pointer b );
|
||||
|
||||
struct cons_pointer multiply_integers( struct cons_pointer a, struct cons_pointer b);
|
||||
struct cons_pointer multiply_integers( struct cons_pointer a,
|
||||
struct cons_pointer b );
|
||||
|
||||
struct cons_pointer integer_to_string( struct cons_pointer int_pointer,
|
||||
int base );
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -411,8 +411,9 @@ struct cons_pointer inverse( struct cons_pointer frame,
|
|||
case RATIOTV:
|
||||
result = make_ratio( frame,
|
||||
make_integer( 0 -
|
||||
to_long_int( cell.payload.ratio.
|
||||
dividend ), NIL ),
|
||||
to_long_int( cell.payload.
|
||||
ratio.dividend ),
|
||||
NIL ),
|
||||
cell.payload.ratio.divisor );
|
||||
break;
|
||||
case REALTV:
|
||||
|
|
@ -452,7 +453,8 @@ struct cons_pointer lisp_subtract( struct
|
|||
break;
|
||||
case INTEGERTV:
|
||||
result = make_integer( cell0.payload.integer.value
|
||||
- cell1.payload.integer.value, NIL );
|
||||
- cell1.payload.integer.value,
|
||||
NIL );
|
||||
break;
|
||||
case RATIOTV:{
|
||||
struct cons_pointer tmp =
|
||||
|
|
|
|||
|
|
@ -61,18 +61,18 @@ struct cons_pointer simplify_ratio( struct cons_pointer frame_pointer,
|
|||
|
||||
if ( ratiop( arg ) ) {
|
||||
int64_t ddrv =
|
||||
pointer2cell( pointer2cell( arg ).payload.ratio.dividend ).payload.
|
||||
integer.value, drrv =
|
||||
pointer2cell( pointer2cell( arg ).payload.ratio.divisor ).payload.
|
||||
integer.value, gcd = greatest_common_divisor( ddrv, drrv );
|
||||
pointer2cell( pointer2cell( arg ).payload.ratio.dividend ).
|
||||
payload.integer.value, drrv =
|
||||
pointer2cell( pointer2cell( arg ).payload.ratio.divisor ).
|
||||
payload.integer.value, gcd = greatest_common_divisor( ddrv, drrv );
|
||||
|
||||
if ( gcd > 1 ) {
|
||||
if ( drrv / gcd == 1 ) {
|
||||
result = make_integer( ddrv / gcd , NIL);
|
||||
result = make_integer( ddrv / gcd, NIL );
|
||||
} else {
|
||||
result =
|
||||
make_ratio( frame_pointer, make_integer( ddrv / gcd , NIL),
|
||||
make_integer( drrv / gcd , NIL) );
|
||||
make_ratio( frame_pointer, make_integer( ddrv / gcd, NIL ),
|
||||
make_integer( drrv / gcd, NIL ) );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -106,7 +106,7 @@ struct cons_pointer add_ratio_ratio( struct cons_pointer frame_pointer,
|
|||
if ( ratiop( arg1 ) && ratiop( arg2 ) ) {
|
||||
struct cons_space_object cell1 = pointer2cell( arg1 );
|
||||
struct cons_space_object cell2 = pointer2cell( arg2 );
|
||||
// TODO: to be entirely reworked for bignums. All vars must be lisp integers.
|
||||
// TODO: to be entirely reworked for bignums. All vars must be lisp integers.
|
||||
int64_t dd1v =
|
||||
pointer2cell( cell1.payload.ratio.dividend ).payload.integer.value,
|
||||
dd2v =
|
||||
|
|
@ -203,10 +203,10 @@ struct cons_pointer divide_ratio_ratio( struct cons_pointer frame_pointer,
|
|||
struct cons_pointer arg1,
|
||||
struct cons_pointer arg2 ) {
|
||||
struct cons_pointer i = make_ratio( frame_pointer,
|
||||
pointer2cell( arg2 ).payload.ratio.
|
||||
divisor,
|
||||
pointer2cell( arg2 ).payload.ratio.
|
||||
dividend ), result =
|
||||
pointer2cell( arg2 ).payload.
|
||||
ratio.divisor,
|
||||
pointer2cell( arg2 ).payload.
|
||||
ratio.dividend ), result =
|
||||
multiply_ratio_ratio( frame_pointer, arg1, i );
|
||||
|
||||
dec_ref( i );
|
||||
|
|
@ -245,7 +245,7 @@ struct cons_pointer multiply_ratio_ratio( struct cons_pointer frame_pointer, str
|
|||
|
||||
struct cons_pointer unsimplified =
|
||||
make_ratio( frame_pointer, make_integer( ddrv, NIL ),
|
||||
make_integer( drrv , NIL) );
|
||||
make_integer( drrv, NIL ) );
|
||||
result = simplify_ratio( frame_pointer, unsimplified );
|
||||
|
||||
if ( !eq( unsimplified, result ) ) {
|
||||
|
|
@ -272,7 +272,7 @@ struct cons_pointer multiply_integer_ratio( struct cons_pointer frame_pointer,
|
|||
struct cons_pointer result;
|
||||
|
||||
if ( integerp( intarg ) && ratiop( ratarg ) ) {
|
||||
struct cons_pointer one = make_integer( 1, NIL),
|
||||
struct cons_pointer one = make_integer( 1, NIL ),
|
||||
ratio = make_ratio( frame_pointer, intarg, one );
|
||||
result = multiply_ratio_ratio( frame_pointer, ratio, ratarg );
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue