Skip to content

Commit 86c9f7f

Browse files
cbmarinijodavies
authored andcommitted
fix: fixes the ToRational statement.
- The statement could produce 1/0 for small floats (i.e. rationals close to zero). These are now properly handled and set to zero.
1 parent c968a9e commit 86c9f7f

File tree

2 files changed

+85
-9
lines changed

2 files changed

+85
-9
lines changed

check/features.frm

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1463,6 +1463,73 @@ assert result("ATANH") =~ expr("
14631463
- 6.08698087464190136361e-01*atanh( - 5.4321e-01)
14641464
")
14651465
*--#] evaluate_atanh :
1466+
*--#[ torat :
1467+
#-
1468+
#StartFloat 16d
1469+
Symbol a,b,jj;
1470+
Local F1 = 0.0
1471+
-10^-20*a
1472+
+1023/1024*a^2
1473+
-17/1024*a^3
1474+
+3602879701896397/2^55*a^4
1475+
-10^20*a^5
1476+
+17*a^6
1477+
;
1478+
Local F2 = sum_(jj,1,16,(355/113+10^-jj)*a^jj);
1479+
Local F3 = 0.3*a^1+0.33*a^2+0.333*a^3+0.3333*a^4+0.33333*a^5+0.333333*a^6+0.3333333*a^7+0.33333333*a^8+0.333333333*a^9+0.3333333333*a^10+0.33333333333*a^11+0.333333333333*a^12+0.3333333333333*a^13+0.33333333333333*a^14+0.333333333333333*a^15+0.3333333333333333*a^16;
1480+
ToFloat;
1481+
.sort
1482+
1483+
ToRat;
1484+
.sort
1485+
1486+
#StartFloat 50d
1487+
Local F4 = 10e-20;
1488+
ToRat;
1489+
Print +s;
1490+
.end
1491+
#pend_if wordsize == 2
1492+
assert succeeded?
1493+
assert result("F1") =~ expr("+ 1023/1024*a^2
1494+
- 17/1024*a^3
1495+
+ 1/10*a^4
1496+
- 100000000000000000000*a^5
1497+
+ 17*a^6")
1498+
assert result("F2") =~ expr("+ 3663/1130*a
1499+
+ 35613/11300*a^2
1500+
+ 355113/113000*a^3
1501+
+ 3550113/1130000*a^4
1502+
+ 35500113/11300000*a^5
1503+
+ 355000113/113000000*a^6
1504+
+ 2205176720676/701929469027*a^7
1505+
+ 5798543718053/1845733628322*a^8
1506+
+ 4781671236789/1522053097423*a^9
1507+
+ 492368235747/156725663768*a^10
1508+
+ 355/113*a^11
1509+
+ 355/113*a^12
1510+
+ 355/113*a^13
1511+
+ 355/113*a^14
1512+
+ 355/113*a^15
1513+
+ 355/113*a^16")
1514+
assert result("F3") =~ expr("
1515+
+ 3/10*a
1516+
+ 33/100*a^2
1517+
+ 333/1000*a^3
1518+
+ 3333/10000*a^4
1519+
+ 33333/100000*a^5
1520+
+ 333333/1000000*a^6
1521+
+ 3333333/10000000*a^7
1522+
+ 33333333/100000000*a^8
1523+
+ 1/3*a^9
1524+
+ 1/3*a^10
1525+
+ 1/3*a^11
1526+
+ 1/3*a^12
1527+
+ 1/3*a^13
1528+
+ 1/3*a^14
1529+
+ 1/3*a^15
1530+
+ 1/3*a^16")
1531+
assert result("F4") =~ expr("+ 1/10000000000000000000")
1532+
*--#] torat :
14661533
*--#[ strictrounding_1 :
14671534
#StartFloat 6d
14681535
CFunction f;

sources/float.c

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,7 @@ long FloatToInteger(UWORD *out, mpf_t floatin, long *bitsused)
591591
mpz_set_f(z,floatin);
592592
ZtoForm(out,&nout,z);
593593
mpz_clear(z);
594-
x = out[0]; nx = 0;
594+
x = out[nout-1]; nx = 0;
595595
while ( x ) { nx++; x >>= 1; }
596596
*bitsused = (nout-1)*BITSINWORD + nx;
597597
return(nout);
@@ -678,7 +678,7 @@ int FloatToRat(UWORD *ratout, WORD *nratout, mpf_t floatin)
678678
WORD na, nb, nc, nd, i;
679679
int nout;
680680
LONG oldpWorkPointer = AT.pWorkPointer;
681-
long bitsused = 0, totalbitsused = 0, totalbits = AC.DefaultPrecision;
681+
long bitsused = 0, totalbitsused = 0, totalbits = AC.DefaultPrecision-AC.MaxWeight-1;
682682
int retval = 0, startnul;
683683
WantAddPointers(AC.DefaultPrecision); /* Horrible overkill */
684684
AT.pWorkSpace[AT.pWorkPointer++] = out;
@@ -710,15 +710,24 @@ int FloatToRat(UWORD *ratout, WORD *nratout, mpf_t floatin)
710710
else {
711711
nout = FloatToInteger((UWORD *)out,aux1,&bitsused);
712712
out += nout;
713-
totalbitsused += bitsused;
714713
}
715714
if ( bitsused > (totalbits-totalbitsused)/2 ) { break; }
716715
if ( mpf_sgn(aux2) == 0 ) {
717716
/*if ( startnul == 1 )*/ AT.pWorkSpace[AT.pWorkPointer++] = out;
718717
break;
719718
}
719+
totalbitsused += bitsused;
720720
AT.pWorkSpace[AT.pWorkPointer++] = out;
721721
}
722+
/*
723+
For |floatin| << 1, we have startnul = 1 and hit the precision guard
724+
already on the first continued-fraction step. The resulting float is
725+
therefore close to the rational 0/1 and we can immediately return.
726+
*/
727+
if ( startnul == 1 && AT.pWorkPointer == oldpWorkPointer + 2 ) {
728+
*ratout++ = 0; *ratout++ = 1; *ratout = *nratout = 3;
729+
goto ret;
730+
}
722731
/*
723732
At this point we have the function with the repeated fraction.
724733
Now we should work out the fraction. Form code would be:
@@ -734,11 +743,6 @@ int FloatToRat(UWORD *ratout, WORD *nratout, mpf_t floatin)
734743
na = 1; a[0] = 1;
735744
c = (UWORD *)(AT.pWorkSpace[--AT.pWorkPointer]);
736745
nc = nb = ((UWORD *)out)-c;
737-
if ( nc > 10 ) {
738-
mc = c;
739-
c = (UWORD *)(AT.pWorkSpace[--AT.pWorkPointer]);
740-
nc = nb = ((UWORD *)mc)-c;
741-
}
742746
for ( i = 0; i < nb; i++ ) b[i] = c[i];
743747
mc = c = NumberMalloc("FloatToRat");
744748
while ( AT.pWorkPointer > oldpWorkPointer ) {
@@ -791,12 +795,13 @@ int FloatToRat(UWORD *ratout, WORD *nratout, mpf_t floatin)
791795
if ( s < 0 ) mpf_neg(floatin,floatin);
792796
/*
793797
{
794-
WORD n = *ratout;
798+
WORD n = *nratout;
795799
RatToFloat(aux1,ratout,n);
796800
mpf_sub(aux2,floatin,aux1);
797801
gmp_printf("Diff is %.*Fe\n",40,aux2);
798802
}
799803
*/
804+
ret:
800805
return(retval);
801806
}
802807

@@ -1492,7 +1497,11 @@ int ToRat(PHEAD WORD *term, WORD level)
14921497
The result can go straight over the float_ function.
14931498
*/
14941499
UnpackFloat(aux4,t);
1500+
// If aux4 is zero, the term vanishes
1501+
if ( mpf_sgn(aux4) == 0 ) return(0);
14951502
if ( FloatToRat((UWORD *)t,&ncoef,aux4) == 0 ) {
1503+
// Check if the resulting rational is zero
1504+
if ( t[0] == 0 && t[1] == 1 && ncoef == 3 ) return(0);
14961505
t += ABS(ncoef);
14971506
t[-1] = ncoef*nsign;
14981507
*term = t - term;

0 commit comments

Comments
 (0)