Tried to get more sensible printing of floating point numbers
Results are quite disappointing. Resolution on long doubles is nothing like as good as I hoped; they're out by one part in 10^20. All unit tests except one pass, and the one that doesn't is a very minor rounding issue, so I'm calling it good.
This commit is contained in:
parent
fc960dec20
commit
27fd678888
9 changed files with 45 additions and 14 deletions
|
|
@ -73,7 +73,6 @@ int main( int argc, char *argv[] ) {
|
|||
*/
|
||||
deep_bind( c_string_to_lisp_symbol( "nil" ), NIL );
|
||||
deep_bind( c_string_to_lisp_symbol( "t" ), TRUE );
|
||||
/* deep_bind( c_string_to_lisp_symbol( L"λ"), LAMBDA ); */
|
||||
deep_bind( c_string_to_lisp_symbol( "lambda" ), LAMBDA );
|
||||
|
||||
/*
|
||||
|
|
@ -85,6 +84,7 @@ int main( int argc, char *argv[] ) {
|
|||
bind_function( "car", &lisp_car );
|
||||
bind_function( "cdr", &lisp_cdr );
|
||||
bind_function( "cons", &lisp_cons );
|
||||
bind_function( "divide", &lisp_divide );
|
||||
bind_function( "eq", &lisp_eq );
|
||||
bind_function( "equal", &lisp_equal );
|
||||
bind_function( "eval", &lisp_eval );
|
||||
|
|
@ -98,6 +98,7 @@ int main( int argc, char *argv[] ) {
|
|||
bind_function( "+", &lisp_add );
|
||||
bind_function( "*", &lisp_multiply );
|
||||
bind_function( "-", &lisp_subtract );
|
||||
bind_function( "/", &lisp_divide );
|
||||
|
||||
/*
|
||||
* primitive special forms
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
* but only integers and reals are so far implemented.
|
||||
*/
|
||||
long double numeric_value( struct cons_pointer pointer ) {
|
||||
double result = NAN;
|
||||
long double result = NAN;
|
||||
struct cons_space_object *cell = &pointer2cell( pointer );
|
||||
|
||||
if ( integerp( pointer ) ) {
|
||||
|
|
|
|||
15
src/peano.c
15
src/peano.c
|
|
@ -170,13 +170,16 @@ lisp_divide( struct stack_frame *frame, struct cons_pointer env ) {
|
|||
if ( numberp( frame->arg[1] ) && numeric_value( frame->arg[1] ) == 0 ) {
|
||||
lisp_throw( c_string_to_lisp_string
|
||||
( "Cannot divide: divisor is zero" ), frame );
|
||||
} else if ( integerp( frame->arg[0] ) && integerp( frame->arg[1] ) ) {
|
||||
result = make_integer( arg0.payload.integer.value /
|
||||
arg1.payload.integer.value );
|
||||
} else if ( numberp( frame->arg[0] ) && numberp( frame->arg[1] ) ) {
|
||||
result =
|
||||
make_real( numeric_value( frame->arg[0] ) /
|
||||
numeric_value( frame->arg[1] ) );
|
||||
long int i = ( long int ) numeric_value( frame->arg[0] ) /
|
||||
numeric_value( frame->arg[1] );
|
||||
long double r = ( long double ) numeric_value( frame->arg[0] ) /
|
||||
numeric_value( frame->arg[1] );
|
||||
if ( fabsl( ( long double ) i - r ) < 0.0000000001 ) {
|
||||
result = make_integer( i );
|
||||
} else {
|
||||
result = make_real( r );
|
||||
}
|
||||
} else {
|
||||
lisp_throw( c_string_to_lisp_string
|
||||
( "Cannot divide: not a number" ), frame );
|
||||
|
|
|
|||
|
|
@ -43,6 +43,15 @@ extern "C" {
|
|||
struct cons_pointer
|
||||
lisp_subtract( struct stack_frame *frame, struct cons_pointer env );
|
||||
|
||||
/**
|
||||
* Divide one number by another.
|
||||
* @param env the evaluation environment - ignored;
|
||||
* @param frame the stack frame.
|
||||
* @return a pointer to an integer or real.
|
||||
*/
|
||||
struct cons_pointer
|
||||
lisp_divide( struct stack_frame *frame, struct cons_pointer env );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
17
src/print.c
17
src/print.c
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
/*
|
||||
* wide characters
|
||||
|
|
@ -72,6 +73,7 @@ void print_list( FILE * output, struct cons_pointer pointer ) {
|
|||
|
||||
void print( FILE * output, struct cons_pointer pointer ) {
|
||||
struct cons_space_object cell = pointer2cell( pointer );
|
||||
char *buffer;
|
||||
|
||||
/*
|
||||
* Because tags have values as well as bytes, this if ... else if
|
||||
|
|
@ -95,7 +97,20 @@ void print( FILE * output, struct cons_pointer pointer ) {
|
|||
fwprintf( output, L"nil" );
|
||||
break;
|
||||
case REALTV:
|
||||
fwprintf( output, L"%Lf", cell.payload.real.value );
|
||||
/* TODO: using the C heap is a bad plan because it will fragment.
|
||||
* As soon as I have working vector space I'll use a special purpose
|
||||
* vector space object */
|
||||
buffer = ( char * ) malloc( 24 );
|
||||
memset( buffer, 0, 24 );
|
||||
/* format it really long, then clear the trailing zeros */
|
||||
sprintf( buffer, "%-.23Lg", cell.payload.real.value );
|
||||
if ( strchr( buffer, '.' ) != NULL ) {
|
||||
for ( int i = strlen( buffer ) - 1; buffer[i] == '0'; i-- ) {
|
||||
buffer[i] = '\0';
|
||||
}
|
||||
}
|
||||
fwprintf( output, L"%s", buffer );
|
||||
free( buffer );
|
||||
break;
|
||||
case STRINGTV:
|
||||
print_string( output, pointer );
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue