Skip to content

Commit ca137e3

Browse files
committed
feat: add a new chop statement to remove floating point numbers below a given threshold.
- The threshold can be specified as a float, integer or rational.
1 parent 7fa4cef commit ca137e3

File tree

6 files changed

+177
-0
lines changed

6 files changed

+177
-0
lines changed

check/features.frm

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,6 +1415,24 @@ assert result("ATANH") =~ expr("
14151415
- 6.08698087464190136361e-01*atanh( - 5.4321e-01)
14161416
")
14171417
*--#] evaluate_atanh :
1418+
*--#[ chop :
1419+
#StartFloat 15d
1420+
Symbol a,b,c;
1421+
CFunction f,g;
1422+
Local F = 1.0e-10*a+4.7*b+.2e-10*c+f(2,0.000001)+g(2.,1);
1423+
Chop 1.0e-10;
1424+
Argument f;
1425+
Chop 1/10000;
1426+
EndArgument;
1427+
Argument g;
1428+
Chop 7;
1429+
EndArgument;
1430+
Print;
1431+
.end
1432+
#pend_if wordsize == 2
1433+
assert succeeded?
1434+
assert result("F") =~ expr("4.7e+00*b + 1.0e-10*a + f(2,0) + g(0,1)")
1435+
*--#] chop :
14181436
*--#[ float_error :
14191437
Evaluate;
14201438
ToFloat;

sources/compiler.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@ static KEYWORD com2commands[] = {
117117
,{"chainin", (TFUN)CoChainin, STATEMENT, PARTEST}
118118
,{"chainout", (TFUN)CoChainout, STATEMENT, PARTEST}
119119
,{"chisholm", (TFUN)CoChisholm, STATEMENT, PARTEST}
120+
#ifdef WITHFLOAT
121+
,{"chop", (TFUN)CoChop, STATEMENT, PARTEST}
122+
#endif
120123
,{"cleartable", (TFUN)CoClearTable, DECLARATION, PARTEST}
121124
,{"clearflag", (TFUN)CoClearUserFlag, STATEMENT, PARTEST}
122125
,{"collect", (TFUN)CoCollect, SPECIFICATION,PARTEST}

sources/declare.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1732,8 +1732,10 @@ int CoEvaluate(UBYTE *);
17321732
int PrintFloat(WORD *fun,int numdigits);
17331733
int CoToRat(UBYTE *);
17341734
int CoToFloat(UBYTE *);
1735+
int CoChop(UBYTE *);
17351736
int ToRat(PHEAD WORD *,WORD);
17361737
int ToFloat(PHEAD WORD *,WORD);
1738+
int Chop(PHEAD WORD *, WORD);
17371739
WORD FloatFunToRat(PHEAD UWORD *,WORD *);
17381740
int AddWithFloat(PHEAD WORD **,WORD **);
17391741
int MergeWithFloat(PHEAD WORD **,WORD **);

sources/float.c

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,6 +1348,115 @@ int CoToRat(UBYTE *s)
13481348

13491349
/*
13501350
#] CoToRat :
1351+
#[ CoChop :
1352+
1353+
LHS notation of the chop statement:
1354+
TYPECHOP, length, FLOATFUN, ...
1355+
where FLOATFUN, ... represents the threshold of the chop statement in
1356+
the notation of a float_ function with its arguments.
1357+
1358+
*/
1359+
1360+
int CoChop(UBYTE *s)
1361+
{
1362+
GETIDENTITY
1363+
UBYTE *ss, c;
1364+
WORD *w, *OldWork;
1365+
int spec;
1366+
if ( AT.aux_ == 0 ) {
1367+
MesPrint("&Illegal attempt to chop a float_ without activating floating point numbers.");
1368+
MesPrint("&Forgotten %#startfloat instruction?");
1369+
return(1);
1370+
}
1371+
if ( *s == 0 ) {
1372+
MesPrint("&Chop needs a number (float or rational) as an argument.");
1373+
return(1);
1374+
}
1375+
/* Create TYPECHOP header */
1376+
w = OldWork = AT.WorkPointer;
1377+
*w++ = TYPECHOP;
1378+
w++;
1379+
1380+
while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
1381+
1382+
/*
1383+
The argument of chop can be
1384+
1: a floating-point number
1385+
2: an integer or rational number
1386+
*/
1387+
if ( FG.cTable[*s] == 1 || *s == '.' ) {
1388+
/* 1: Attempt to parse as floating-point number */
1389+
ss = CheckFloat(s, &spec);
1390+
if ( ss > s ) {
1391+
/* CheckFloat found a valid float */
1392+
if ( spec == 1 ) { /* Zero */
1393+
MesPrint("&The argument in Chop needs to be larger than 0.");
1394+
return(1);
1395+
}
1396+
else if ( spec == -1 ) {
1397+
MesPrint("&The floating point system has not been started.");
1398+
return(1);
1399+
}
1400+
else {
1401+
AT.WorkPointer = w;
1402+
/*
1403+
Reads the floating point number and outputs it at AT.WorkPointer as if it were a float_
1404+
function with its arguments.
1405+
*/
1406+
ReadFloat((SBYTE *)s);
1407+
s = ss;
1408+
w += w[1];
1409+
}
1410+
}
1411+
else {
1412+
/* 2: CheckFloat didn't find a float, we now try for integers and rationals */
1413+
/* Parse the integer part (numerator for rationals) */
1414+
ss = s;
1415+
while ( FG.cTable[*s] == 1 ) s++; /* Skip over digits */
1416+
c = *s; *s = 0;
1417+
gmp_sscanf((char *)ss, "%Ff", aux1); /* Parse into GMP float */
1418+
if ( mpf_sgn(aux1) == 0 ) {
1419+
MesPrint("&The argument in Chop needs to be larger than 0.");
1420+
return(1);
1421+
}
1422+
*s = c;
1423+
while ( *s == ' ' || *s == '\t' ) s++;
1424+
/* Check for rational number */
1425+
if ( *s == '/' ) {
1426+
s++;
1427+
while ( *s == ' ' || *s == '\t' ) s++;
1428+
/* Parse the denominator */
1429+
if ( FG.cTable[*s] == 1 ) {
1430+
ss = s;
1431+
while ( FG.cTable[*s] == 1 ) s++; /* Skip over digits */
1432+
c = *s; *s = 0;
1433+
gmp_sscanf((char *)ss, "%Ff", aux2);
1434+
*s = c;
1435+
if ( mpf_sgn(aux2) == 0 ) {
1436+
MesPrint("&Division by zero in chop statement.");
1437+
return(1);
1438+
}
1439+
/* Perform the division */
1440+
mpf_div(aux1, aux1, aux2);
1441+
}
1442+
}
1443+
/* Put aux1 in the notation of a float_ function */
1444+
PackFloat(w, aux1);
1445+
w += w[1];
1446+
}
1447+
}
1448+
if ( *s ) {
1449+
MesPrint("&Illegal argument(s) in Chop statement: '%s'",s);
1450+
return(1);
1451+
}
1452+
AT.WorkPointer = OldWork;
1453+
AT.WorkPointer[1] = w - AT.WorkPointer; /* Set total length */
1454+
AddNtoL(AT.WorkPointer[1],AT.WorkPointer); /* Add the LHS to the compiler buffer */
1455+
return(0);
1456+
}
1457+
1458+
/*
1459+
#] CoChop :
13511460
#[ ToFloat :
13521461
13531462
Converts the coefficient to floating point if it is still a rat.
@@ -1416,6 +1525,46 @@ int ToRat(PHEAD WORD *term, WORD level)
14161525

14171526
/*
14181527
#] ToRat :
1528+
#[ Chop :
1529+
1530+
Removes terms with a floating point number smaller than a given threshold.
1531+
1532+
Search for a FLOATFUN and compares its absolute value against the threshold
1533+
specified in the chop statement. This threshold can be obtained from the
1534+
LHS of the chop statement in the compiler buffer.
1535+
1536+
*/
1537+
int Chop(PHEAD WORD *term, WORD level)
1538+
{
1539+
WORD *tstop, *t, nsize, *threshold;
1540+
CBUF *C = cbuf+AM.rbufnum;
1541+
/* Find the float which should be at the end. */
1542+
tstop = term + *term;
1543+
nsize = ABS(tstop[-1]); tstop -= nsize;
1544+
t = term+1;
1545+
while ( t < tstop ) {
1546+
if ( *t == FLOATFUN && t + t[1] == tstop && TestFloat(t) &&
1547+
nsize == 3 && tstop[0] == 1 && tstop[1] == 1 ) break;
1548+
t += t[1];
1549+
}
1550+
if ( t < tstop ) {
1551+
/* Get threshold value from compiler buffer */
1552+
threshold = C->lhs[level];
1553+
threshold += 2; /* Skip TYPECHOP header */
1554+
UnpackFloat(aux5, threshold);
1555+
1556+
/* Extract float and compute its absolute value */
1557+
UnpackFloat(aux4, t);
1558+
mpf_abs(aux4, aux4);
1559+
1560+
/* Remove if < threshold */
1561+
if ( mpf_cmp(aux4, aux5) < 0 ) return(0);
1562+
}
1563+
return(Generator(BHEAD term,level));
1564+
}
1565+
1566+
/*
1567+
#] Chop :
14191568
#] Float Routines :
14201569
#[ Sorting :
14211570

sources/ftypes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,7 @@ typedef int (*TFUN1)();
605605
#define TYPEEXPAND 88
606606
#define TYPETOFLOAT 89
607607
#define TYPETORAT 90
608+
#define TYPECHOP 91
608609
#endif
609610

610611
/*

sources/proces.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3990,6 +3990,10 @@ SkipCount: level++;
39903990
AT.WorkPointer = term + *term;
39913991
if ( ToRat(BHEAD term,level) ) goto GenCall;
39923992
goto Return0;
3993+
case TYPECHOP:
3994+
AT.WorkPointer = term + *term;
3995+
if ( Chop(BHEAD term,level) ) goto GenCall;
3996+
goto Return0;
39933997
#endif
39943998
}
39953999
goto SkipCount;

0 commit comments

Comments
 (0)