Skip to content

Commit 2f983f2

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, rational or power. - added a test and documentation for the chop statement. fix: switched the commands cleartable and clearflag in comm2commands such that they are in alphabetical order.
1 parent 2aba64b commit 2f983f2

File tree

8 files changed

+231
-1
lines changed

8 files changed

+231
-1
lines changed

check/features.frm

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,6 +1415,47 @@ assert result("ATANH") =~ expr("
14151415
- 6.08698087464190136361e-01*atanh( - 5.4321e-01)
14161416
")
14171417
*--#] evaluate_atanh :
1418+
*--#[ chop :
1419+
#StartFloat 15d
1420+
#StartFloat 15d
1421+
Symbol x;
1422+
Local F1 = 4.7*x-1.0e-10*x^2+.2e-10*x^3-0.00005*x^4+x^5/1000000;
1423+
Local F2 = 4.7*x-1.0e-10*x^2+.2e-10*x^3-0.00005*x^4+x^5/1000000;
1424+
Local F3 = 4.7*x-1.0e-10*x^2+.2e-10*x^3-0.00005*x^4+x^5/1000000;
1425+
Local F4 = 4.7*x-1.0e-10*x^2+.2e-10*x^3-0.00005*x^4+x^5/1000000;
1426+
Local F5 = 4.7*x-1.0e-10*x^2+.2e-10*x^3-0.00005*x^4+x^5/1000000;
1427+
Print;
1428+
.sort
1429+
Skip;
1430+
NSkip F1;
1431+
Chop 1.0e-10;
1432+
.sort
1433+
Skip;
1434+
NSkip F2;
1435+
Chop 1/10000;
1436+
.sort
1437+
Skip;
1438+
NSkip F3;
1439+
Chop 7;
1440+
.sort
1441+
Skip;
1442+
NSkip F4;
1443+
Chop 10^-6;
1444+
.sort
1445+
Skip;
1446+
NSkip F5;
1447+
Chop 10^6;
1448+
.sort
1449+
Print;
1450+
.end
1451+
#pend_if wordsize == 2
1452+
assert succeeded?
1453+
assert result("F1") =~ expr("4.7e+00*x - 1.0e-10*x^2 - 5.0e-05*x^4 + 1/1000000*x^5")
1454+
assert result("F2") =~ expr("4.7e+00*x + 1/1000000*x^5")
1455+
assert result("F3") =~ expr("1/1000000*x^5")
1456+
assert result("F4") =~ expr("4.7e+00*x - 5.0e-05*x^4 + 1/1000000*x^5")
1457+
assert result("F5") =~ expr("1/1000000*x^5")
1458+
*--#] chop :
14181459
*--#[ float_error :
14191460
Evaluate;
14201461
ToFloat;

doc/manual/float.tex

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,18 @@ \chapter{Floating point}
5151
arguments are the functions mzv\_, euler\_, sqrt\_ and mzvhalf\_. If any
5252
(or more than one) of these are specified only those functions will be
5353
evaluated.
54+
\item[Chop] This statement removes floating point numbers that are smaller
55+
in absolute magnitude than a specified threshold. It takes one argument delta:
56+
\begin{verbatim}
57+
Chop <delta>;
58+
\end{verbatim}
59+
All floating point numbers with absolute value less than delta are replaced by 0.
60+
Terms with no floating point coefficient are left untouched. The threshold delta
61+
can be a floating point number, integer, rational number, or power. Because
62+
statements in \FORM{} act term by term, it is often important to sort before invoking the
63+
chop statement. Otherwise, terms might be removed individually, while after
64+
sorting and combining, their combined floating point coefficient could exceed
65+
the specified chop threshold.
5466
\item[Format floatprecision] This instruction controls how many digits are
5567
displayed when printing floating point numbers. It only affects output
5668
formatting and does not influence the internal precision or accuracy of

doc/manual/statements.tex

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,18 @@ \section{chisholm}
600600
more details, see chapter \ref{gammaalgebra} on gamma\index{gamma algebra} algebra. \vspace{10mm}
601601

602602
%--#] chisholm :
603+
%--#[ chop :
604+
\section{chop}
605+
\label{substaevaluate}
606+
607+
\noindent \begin{tabular}{ll}
608+
Type & Executable statement\\
609+
Syntax & chop $<$threshold$>$; \\
610+
\end{tabular} \vspace{4mm}
611+
612+
\noindent See chapter~\ref{floatingpoint} on the floating point capability.
613+
614+
%--#] chop :
603615
%--#[ cleartable :
604616

605617
\section{cleartable}

sources/compiler.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,11 @@ static KEYWORD com2commands[] = {
117117
,{"chainin", (TFUN)CoChainin, STATEMENT, PARTEST}
118118
,{"chainout", (TFUN)CoChainout, STATEMENT, PARTEST}
119119
,{"chisholm", (TFUN)CoChisholm, STATEMENT, PARTEST}
120-
,{"cleartable", (TFUN)CoClearTable, DECLARATION, PARTEST}
120+
#ifdef WITHFLOAT
121+
,{"chop", (TFUN)CoChop, STATEMENT, PARTEST}
122+
#endif
121123
,{"clearflag", (TFUN)CoClearUserFlag, STATEMENT, PARTEST}
124+
,{"cleartable", (TFUN)CoClearTable, DECLARATION, PARTEST}
122125
,{"collect", (TFUN)CoCollect, SPECIFICATION,PARTEST}
123126
,{"commuteinset", (TFUN)CoCommuteInSet, DECLARATION, PARTEST}
124127
,{"contract", (TFUN)CoContract, STATEMENT, 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: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,6 +1348,121 @@ 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, pow = 1;
1366+
unsigned long x;
1367+
if ( AT.aux_ == 0 ) {
1368+
MesPrint("&Illegal attempt to chop a float_ without activating floating point numbers.");
1369+
MesPrint("&Forgotten %#startfloat instruction?");
1370+
return(1);
1371+
}
1372+
if ( *s == 0 ) {
1373+
MesPrint("&Chop needs a number (float or rational) as an argument.");
1374+
return(1);
1375+
}
1376+
/* Create TYPECHOP header */
1377+
w = OldWork = AT.WorkPointer;
1378+
*w++ = TYPECHOP;
1379+
w++;
1380+
1381+
while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
1382+
1383+
/*
1384+
The argument of chop can be
1385+
1: a floating-point number
1386+
2: an integer, rational number or power
1387+
*/
1388+
if ( FG.cTable[*s] == 1 || *s == '.' ) {
1389+
/* 1: Attempt to parse as floating-point number */
1390+
ss = CheckFloat(s, &spec);
1391+
if ( ss > s ) {
1392+
/* CheckFloat found a valid float */
1393+
if ( spec == 1 ) { /* Zero */
1394+
MesPrint("&The argument in Chop needs to be larger than 0.");
1395+
return(1);
1396+
}
1397+
else if ( spec == -1 ) {
1398+
MesPrint("&The floating point system has not been started.");
1399+
return(1);
1400+
}
1401+
else {
1402+
AT.WorkPointer = w;
1403+
/*
1404+
Reads the floating point number and outputs it at AT.WorkPointer as if it were a float_
1405+
function with its arguments.
1406+
*/
1407+
ReadFloat((SBYTE *)s);
1408+
s = ss;
1409+
w += w[1];
1410+
}
1411+
}
1412+
else {
1413+
/* 2: CheckFloat didn't find a float, we now try for integers and rationals */
1414+
/* Parse the integer part (numerator for rationals) */
1415+
ss = s;
1416+
while ( FG.cTable[*s] == 1 ) s++; /* Skip over digits */
1417+
c = *s; *s = 0;
1418+
gmp_sscanf((char *)ss, "%Ff", aux1); /* Parse into GMP float */
1419+
if ( mpf_sgn(aux1) == 0 ) {
1420+
MesPrint("&The argument in Chop needs to be larger than 0.");
1421+
return(1);
1422+
}
1423+
*s = c;
1424+
while ( *s == ' ' || *s == '\t' ) s++;
1425+
/* Check for rational number or power*/
1426+
if ( *s == '/' || *s == '^' ) {
1427+
c = *s; s++;
1428+
while ( *s == ' ' || *s == '\t' ) s++;
1429+
if ( *s == '-' ) { s++; pow = -1; } /* negative power */
1430+
/* Parse the denominator or power */
1431+
if ( FG.cTable[*s] == 1 ) {
1432+
ParseNumber(x,s)
1433+
if ( c == '/' ) { /* rational */
1434+
if ( x == 0 ) {
1435+
MesPrint("&Division by zero in chop statement.");
1436+
return(1);
1437+
}
1438+
/* Perform the division */
1439+
mpf_div_ui(aux1, aux1,x);
1440+
}
1441+
else { /* Power */
1442+
mpf_pow_ui(aux1,aux1,x);
1443+
if ( pow == -1 ) {
1444+
mpf_ui_div(aux1,(unsigned long) 1, aux1);
1445+
}
1446+
}
1447+
}
1448+
}
1449+
/* Put aux1 in the notation of a float_ function */
1450+
PackFloat(w, aux1);
1451+
w += w[1];
1452+
}
1453+
}
1454+
if ( *s ) {
1455+
MesPrint("&Illegal argument(s) in Chop statement: '%s'",s);
1456+
return(1);
1457+
}
1458+
AT.WorkPointer = OldWork;
1459+
AT.WorkPointer[1] = w - AT.WorkPointer; /* Set total length */
1460+
AddNtoL(AT.WorkPointer[1],AT.WorkPointer); /* Add the LHS to the compiler buffer */
1461+
return(0);
1462+
}
1463+
1464+
/*
1465+
#] CoChop :
13511466
#[ ToFloat :
13521467
13531468
Converts the coefficient to floating point if it is still a rat.
@@ -1416,6 +1531,46 @@ int ToRat(PHEAD WORD *term, WORD level)
14161531

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

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)