add_ratio_ratio fixed.

This commit is contained in:
Simon Brooke 2026-02-15 17:38:54 +00:00
parent d7e0220674
commit 169afc9eb4
3 changed files with 53 additions and 68 deletions

View file

@ -1,5 +1,27 @@
# State of Play # State of Play
## 20260215
Both of yesterday's regressions are fixed. Memory problem still in much the
same state.
> Allocation summary: allocated 1210; deallocated 10; not deallocated 1200.
That left the add ratios problem which was deeper. I had unintended unterminated
recursion happening there. :-(
It burned through 74 cons pages each of 1,024 cons cells, total 76,800 cells,
and 19,153 stack frames. before it got there; and then threw the exception back
up through each of those 19,153 stack frames. But the actual exception message
was `Unrecognised tag value 0 ( )`, which is not enormously helpful.
However, once I had recognised what the problem was, it was quickly fixed, with
the added bonus that the new solution will automatically work for bignum
fractions once bignums are working.
So we're down to eight unit tests failing: the memory leak, one unimplemented
feature, and the bignum problem.
## 20260214 ## 20260214
### Memory leaks ### Memory leaks

View file

@ -25,7 +25,7 @@
/** /**
* return, as a int64_t, the greatest common divisor of `m` and `n`, * @brief return, as an int64_t, the greatest common divisor of `m` and `n`,
*/ */
int64_t greatest_common_divisor( int64_t m, int64_t n ) { int64_t greatest_common_divisor( int64_t m, int64_t n ) {
int o; int o;
@ -39,7 +39,7 @@ int64_t greatest_common_divisor( int64_t m, int64_t n ) {
} }
/** /**
* return, as a int64_t, the least common multiple of `m` and `n`, * @brief return, as an int64_t, the least common multiple of `m` and `n`,
*/ */
int64_t least_common_multiple( int64_t m, int64_t n ) { int64_t least_common_multiple( int64_t m, int64_t n ) {
return m / greatest_common_divisor( m, n ) * n; return m / greatest_common_divisor( m, n ) * n;
@ -64,7 +64,7 @@ struct cons_pointer simplify_ratio( struct cons_pointer pointer ) {
if ( gcd > 1 ) { if ( gcd > 1 ) {
if ( drrv / gcd == 1 ) { if ( drrv / gcd == 1 ) {
result = acquire_integer( ddrv / gcd, NIL ); result = acquire_integer( (int64_t)(ddrv / gcd), NIL );
} else { } else {
debug_printf( DEBUG_ARITH, debug_printf( DEBUG_ARITH,
L"simplify_ratio: %ld/%ld => %ld/%ld\n", L"simplify_ratio: %ld/%ld => %ld/%ld\n",
@ -91,61 +91,26 @@ struct cons_pointer simplify_ratio( struct cons_pointer pointer ) {
*/ */
struct cons_pointer add_ratio_ratio( struct cons_pointer arg1, struct cons_pointer add_ratio_ratio( struct cons_pointer arg1,
struct cons_pointer arg2 ) { struct cons_pointer arg2 ) {
struct cons_pointer r, result; struct cons_pointer r;
debug_print( L"\naadd_ratio_ratio: ", DEBUG_ARITH); debug_print( L"\nadd_ratio_ratio: ", DEBUG_ARITH);
debug_print_object( arg1, DEBUG_ARITH); debug_print_object( arg1, DEBUG_ARITH);
debug_print( L" + ", DEBUG_ARITH); debug_print( L" + ", DEBUG_ARITH);
debug_print_object( arg2, DEBUG_ARITH); debug_print_object( arg2, DEBUG_ARITH);
if ( ratiop( arg1 ) && ratiop( arg2 ) ) { if ( ratiop( arg1 ) && ratiop( arg2 ) ) {
struct cons_space_object cell1 = pointer2cell( arg1 ); struct cons_space_object * cell1 = &pointer2cell( arg1 );
struct cons_space_object cell2 = pointer2cell( arg2 ); struct cons_space_object * cell2 = &pointer2cell( arg2 );
int64_t dd1v =
pointer2cell( cell1.payload.ratio.dividend ).payload.integer.value,
dd2v =
pointer2cell( cell2.payload.ratio.dividend ).payload.integer.value,
dr1v =
pointer2cell( cell1.payload.ratio.divisor ).payload.integer.value,
dr2v =
pointer2cell( cell2.payload.ratio.divisor ).payload.integer.value,
lcm = least_common_multiple( dr1v, dr2v ),
m1 = lcm / dr1v, m2 = lcm / dr2v;
debug_printf( DEBUG_ARITH, L"; lcm = %ld; m1 = %ld; m2 = %ld", lcm, struct cons_pointer divisor = multiply_integers( cell1->payload.ratio.divisor, cell2->payload.ratio.divisor );
m1, m2 ); struct cons_pointer dividend = add_integers(
multiply_integers( cell1->payload.ratio.dividend,
if ( dr1v == dr2v ) { cell2->payload.ratio.divisor),
r = make_ratio( acquire_integer( dd1v + dd2v, NIL ), multiply_integers( cell2->payload.ratio.dividend,
cell1.payload.ratio.divisor ); cell1->payload.ratio.divisor));
} else { r = make_ratio( dividend, divisor );
struct cons_pointer dd1vm = acquire_integer( dd1v * m1, NIL ),
dr1vm = acquire_integer( dr1v * m1, NIL ),
dd2vm = acquire_integer( dd2v * m2, NIL ),
dr2vm = acquire_integer( dr2v * m2, NIL ),
r1 = make_ratio( dd1vm, dr1vm ),
r2 = make_ratio( dd2vm, dr2vm );
r = add_ratio_ratio( r1, r2 );
if ( !eq( r, r1 ) ) {
dec_ref( r1 );
}
if ( !eq( r, r2 ) ) {
dec_ref( r2 );
}
/* because the references on dd1vm, dr1vm, dd2vm and dr2vm were
* never incremented except when making r1 and r2, decrementing
* r1 and r2 should be enought to garbage collect them. */
}
result = simplify_ratio( r );
if ( !eq( r, result ) ) {
dec_ref( r );
}
} else { } else {
result = r =
throw_exception( make_cons( c_string_to_lisp_string throw_exception( make_cons( c_string_to_lisp_string
( L"Shouldn't happen: bad arg to add_ratio_ratio" ), ( L"Shouldn't happen: bad arg to add_ratio_ratio" ),
make_cons( arg1, make_cons( arg1,
@ -153,11 +118,11 @@ struct cons_pointer add_ratio_ratio( struct cons_pointer arg1,
NIL ); NIL );
} }
debug_print( L" => ", DEBUG_ARITH ); debug_print( L"add_ratio_ratio => ", DEBUG_ARITH );
debug_print_object( result, DEBUG_ARITH ); debug_print_object( r, DEBUG_ARITH );
debug_print( L"\n", DEBUG_ARITH ); debug_print( L"\n", DEBUG_ARITH );
return result; return r;
} }

View file

@ -1,13 +1,13 @@
#!/bin/bash #!/bin/bash
return=0 result=0
##################################################################### #####################################################################
# last 'smallnum' value: # last 'smallnum' value:
# sbcl calculates (expt 2 59) => 576460752303423488 # sbcl calculates (expt 2 59) => 576460752303423488
expected='576460752303423488' expected='576460752303423488'
output=`target/psse <<EOF output=`target/psse 2>/dev/null <<EOF
(progn (progn
(set! expt (lambda (set! expt (lambda
(n x) (n x)
@ -26,7 +26,7 @@ then
echo "OK" echo "OK"
else else
echo "Fail: expected '${expected}', got '${actual}'" echo "Fail: expected '${expected}', got '${actual}'"
return=1 result=`echo "${result} + 1" | bc`
fi fi
##################################################################### #####################################################################
@ -34,7 +34,7 @@ fi
# sbcl calculates (expt 2 60) => 1152921504606846976 # sbcl calculates (expt 2 60) => 1152921504606846976
expected='1152921504606846976' expected='1152921504606846976'
output=`target/psse <<EOF output=`target/psse 2>/dev/null <<EOF
(progn (progn
(set! expt (lambda (set! expt (lambda
(n x) (n x)
@ -53,7 +53,7 @@ then
echo "OK" echo "OK"
else else
echo "Fail: expected '${expected}', got '${actual}'" echo "Fail: expected '${expected}', got '${actual}'"
return=1 result=`echo "${result} + 1" | bc`
fi fi
##################################################################### #####################################################################
@ -61,7 +61,7 @@ fi
# sbcl calculates (expt 2 61) => 2305843009213693952 # sbcl calculates (expt 2 61) => 2305843009213693952
expected='2305843009213693952' expected='2305843009213693952'
output=`target/psse <<EOF output=`target/psse 2>/dev/null <<EOF
(progn (progn
(set! expt (lambda (set! expt (lambda
(n x) (n x)
@ -80,15 +80,13 @@ then
echo "OK" echo "OK"
else else
echo "Fail: expected '${expected}', got '${actual}'" echo "Fail: expected '${expected}', got '${actual}'"
return=1 result=`echo "${result} + 1" | bc`
fi fi
# sbcl calculates (expt 2 64) => 18446744073709551616 # sbcl calculates (expt 2 64) => 18446744073709551616
expected='18446744073709551616' expected='18446744073709551616'
output=`target/psse <<EOF output=`target/psse 2>/dev/null <<EOF
(progn (progn
(set! expt (lambda (set! expt (lambda
(n x) (n x)
@ -107,13 +105,13 @@ then
echo "OK" echo "OK"
else else
echo "Fail: expected '${expected}', got '${actual}'" echo "Fail: expected '${expected}', got '${actual}'"
return=1 result=`echo "${result} + 1" | bc`
fi fi
# sbcl calculates (expt 2 65) => 36893488147419103232 # sbcl calculates (expt 2 65) => 36893488147419103232
expected='36893488147419103232' expected='36893488147419103232'
output=`target/psse <<EOF output=`target/psse 2>/dev/null <<EOF
(progn (progn
(set! expt (lambda (set! expt (lambda
(n x) (n x)
@ -132,7 +130,7 @@ then
echo "OK" echo "OK"
else else
echo "Fail: expected '${expected}', got '${actual}'" echo "Fail: expected '${expected}', got '${actual}'"
return=1 result=`echo "${result} + 1" | bc`
fi fi
exit ${return} exit ${result}