Skip to content

Commit fe4a9cc

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 01a66ec commit fe4a9cc

File tree

8 files changed

+230
-1
lines changed

8 files changed

+230
-1
lines changed

check/features.frm

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1435,6 +1435,47 @@ assert succeeded?
14351435
assert result("F1") =~ expr("1.23457e-04 + f(1.0e+00) + f(1.0e+00)")
14361436
assert result("F2") =~ expr("1.235e-04 + 2*f(1.0e+00)")
14371437
*--#] strictrounding :
1438+
*--#[ chop :
1439+
#StartFloat 15d
1440+
#StartFloat 15d
1441+
Symbol x;
1442+
Local F1 = 4.7*x-1.0e-10*x^2+.2e-10*x^3-0.00005*x^4+x^5/1000000;
1443+
Local F2 = 4.7*x-1.0e-10*x^2+.2e-10*x^3-0.00005*x^4+x^5/1000000;
1444+
Local F3 = 4.7*x-1.0e-10*x^2+.2e-10*x^3-0.00005*x^4+x^5/1000000;
1445+
Local F4 = 4.7*x-1.0e-10*x^2+.2e-10*x^3-0.00005*x^4+x^5/1000000;
1446+
Local F5 = 4.7*x-1.0e-10*x^2+.2e-10*x^3-0.00005*x^4+x^5/1000000;
1447+
Print;
1448+
.sort
1449+
Skip;
1450+
NSkip F1;
1451+
Chop 1.0e-10;
1452+
.sort
1453+
Skip;
1454+
NSkip F2;
1455+
Chop 1/10000;
1456+
.sort
1457+
Skip;
1458+
NSkip F3;
1459+
Chop 7;
1460+
.sort
1461+
Skip;
1462+
NSkip F4;
1463+
Chop 10^-6;
1464+
.sort
1465+
Skip;
1466+
NSkip F5;
1467+
Chop 10^6;
1468+
.sort
1469+
Print;
1470+
.end
1471+
#pend_if wordsize == 2
1472+
assert succeeded?
1473+
assert result("F1") =~ expr("4.7e+00*x - 1.0e-10*x^2 - 5.0e-05*x^4 + 1/1000000*x^5")
1474+
assert result("F2") =~ expr("4.7e+00*x + 1/1000000*x^5")
1475+
assert result("F3") =~ expr("1/1000000*x^5")
1476+
assert result("F4") =~ expr("4.7e+00*x - 5.0e-05*x^4 + 1/1000000*x^5")
1477+
assert result("F5") =~ expr("1/1000000*x^5")
1478+
*--#] chop :
14381479
*--#[ float_error :
14391480
Evaluate;
14401481
ToFloat;

doc/manual/float.tex

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,18 @@ \chapter{Floating point}
8989
$1.1100110101011111101*2^{-14}$. When rounded to 5 bits, this becomes
9090
$1.1101*2^{-14}$, which in decimal digits appears as
9191
1.10626220703125e-04.
92+
\item[Chop] This statement removes floating point numbers that are smaller
93+
in absolute magnitude than a specified threshold. It takes one argument delta:
94+
\begin{verbatim}
95+
Chop <delta>;
96+
\end{verbatim}
97+
All floating point numbers with absolute value less than delta are replaced by 0.
98+
Terms with no floating point coefficient are left untouched. The threshold delta
99+
can be a floating point number, integer, rational number, or power. Because
100+
statements in \FORM{} act term by term, it is often important to sort before invoking the
101+
chop statement. Otherwise, terms might be removed individually, while after
102+
sorting and combining, their combined floating point coefficient could exceed
103+
the specified chop threshold.
92104
\item[Format floatprecision] This instruction controls how many digits are
93105
displayed when printing floating point numbers. It only affects output
94106
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: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,6 +1395,120 @@ int CoStrictRounding(UBYTE *s)
13951395
}
13961396
/*
13971397
#] CoStrictRounding :
1398+
#[ CoChop :
1399+
1400+
LHS notation of the chop statement:
1401+
TYPECHOP, length, FLOATFUN, ...
1402+
where FLOATFUN, ... represents the threshold of the chop statement in
1403+
the notation of a float_ function with its arguments.
1404+
1405+
*/
1406+
1407+
int CoChop(UBYTE *s)
1408+
{
1409+
GETIDENTITY
1410+
UBYTE *ss, c;
1411+
WORD *w, *OldWork;
1412+
int spec, pow = 1;
1413+
unsigned long x;
1414+
if ( AT.aux_ == 0 ) {
1415+
MesPrint("&Illegal attempt to chop a float_ without activating floating point numbers.");
1416+
MesPrint("&Forgotten %#startfloat instruction?");
1417+
return(1);
1418+
}
1419+
if ( *s == 0 ) {
1420+
MesPrint("&Chop needs a number (float or rational) as an argument.");
1421+
return(1);
1422+
}
1423+
/* Create TYPECHOP header */
1424+
w = OldWork = AT.WorkPointer;
1425+
*w++ = TYPECHOP;
1426+
w++;
1427+
1428+
while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
1429+
1430+
/*
1431+
The argument of chop can be
1432+
1: a floating-point number
1433+
2: an integer, rational number or power
1434+
*/
1435+
if ( FG.cTable[*s] == 1 || *s == '.' ) {
1436+
/* 1: Attempt to parse as floating-point number */
1437+
ss = CheckFloat(s, &spec);
1438+
if ( ss > s ) {
1439+
/* CheckFloat found a valid float */
1440+
if ( spec == 1 ) { /* Zero */
1441+
MesPrint("&The argument in Chop needs to be larger than 0.");
1442+
return(1);
1443+
}
1444+
else if ( spec == -1 ) {
1445+
MesPrint("&The floating point system has not been started.");
1446+
return(1);
1447+
}
1448+
else {
1449+
AT.WorkPointer = w;
1450+
/*
1451+
Reads the floating point number and outputs it at AT.WorkPointer as if it were a float_
1452+
function with its arguments.
1453+
*/
1454+
ReadFloat((SBYTE *)s);
1455+
s = ss;
1456+
w += w[1];
1457+
}
1458+
}
1459+
else {
1460+
/* 2: CheckFloat didn't find a float, we now try for rationals and powers */
1461+
/* Parse the integer part (numerator for rationals) */
1462+
if ( FG.cTable[*s] == 1 ) {
1463+
ParseNumber(x,s)
1464+
mpf_set_ui(aux1,x);
1465+
}
1466+
if ( mpf_sgn(aux1) == 0 ) {
1467+
MesPrint("&The argument in Chop needs to be larger than 0.");
1468+
return(1);
1469+
}
1470+
while ( *s == ' ' || *s == '\t' ) s++;
1471+
/* Check for rational number or power*/
1472+
if ( *s == '/' || *s == '^' ) {
1473+
c = *s; s++;
1474+
while ( *s == ' ' || *s == '\t' ) s++;
1475+
if ( *s == '-' ) { s++; pow = -1; } /* negative power */
1476+
/* Parse the denominator or power */
1477+
if ( FG.cTable[*s] == 1 ) {
1478+
ParseNumber(x,s)
1479+
if ( c == '/' ) { /* rational */
1480+
if ( x == 0 ) {
1481+
MesPrint("&Division by zero in chop statement.");
1482+
return(1);
1483+
}
1484+
/* Perform the division */
1485+
mpf_div_ui(aux1, aux1,x);
1486+
}
1487+
else { /* Power */
1488+
mpf_pow_ui(aux1,aux1,x);
1489+
if ( pow == -1 ) {
1490+
mpf_ui_div(aux1,(unsigned long) 1, aux1);
1491+
}
1492+
}
1493+
}
1494+
}
1495+
/* Put aux1 in the notation of a float_ function */
1496+
PackFloat(w, aux1);
1497+
w += w[1];
1498+
}
1499+
}
1500+
if ( *s ) {
1501+
MesPrint("&Illegal argument(s) in Chop statement: '%s'",s);
1502+
return(1);
1503+
}
1504+
AT.WorkPointer = OldWork;
1505+
AT.WorkPointer[1] = w - AT.WorkPointer; /* Set total length */
1506+
AddNtoL(AT.WorkPointer[1],AT.WorkPointer); /* Add the LHS to the compiler buffer */
1507+
return(0);
1508+
}
1509+
1510+
/*
1511+
#] CoChop :
13981512
#[ ToFloat :
13991513
14001514
Converts the coefficient to floating point if it is still a rat.
@@ -1521,6 +1635,46 @@ int StrictRounding(PHEAD WORD *term, WORD level, WORD prec, WORD base) {
15211635
}
15221636
/*
15231637
#] StrictRounding :
1638+
#[ Chop :
1639+
1640+
Removes terms with a floating point number smaller than a given threshold.
1641+
1642+
Search for a FLOATFUN and compares its absolute value against the threshold
1643+
specified in the chop statement. This threshold can be obtained from the
1644+
LHS of the chop statement in the compiler buffer.
1645+
1646+
*/
1647+
int Chop(PHEAD WORD *term, WORD level)
1648+
{
1649+
WORD *tstop, *t, nsize, *threshold;
1650+
CBUF *C = cbuf+AM.rbufnum;
1651+
/* Find the float which should be at the end. */
1652+
tstop = term + *term;
1653+
nsize = ABS(tstop[-1]); tstop -= nsize;
1654+
t = term+1;
1655+
while ( t < tstop ) {
1656+
if ( *t == FLOATFUN && t + t[1] == tstop && TestFloat(t) &&
1657+
nsize == 3 && tstop[0] == 1 && tstop[1] == 1 ) break;
1658+
t += t[1];
1659+
}
1660+
if ( t < tstop ) {
1661+
/* Get threshold value from compiler buffer */
1662+
threshold = C->lhs[level];
1663+
threshold += 2; /* Skip TYPECHOP header */
1664+
UnpackFloat(aux5, threshold);
1665+
1666+
/* Extract float and compute its absolute value */
1667+
UnpackFloat(aux4, t);
1668+
mpf_abs(aux4, aux4);
1669+
1670+
/* Remove if < threshold */
1671+
if ( mpf_cmp(aux4, aux5) < 0 ) return(0);
1672+
}
1673+
return(Generator(BHEAD term,level));
1674+
}
1675+
1676+
/*
1677+
#] Chop :
15241678
#] Float Routines :
15251679
#[ Sorting :
15261680

sources/ftypes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,7 @@ typedef int (*TFUN1)();
606606
#define TYPETOFLOAT 89
607607
#define TYPETORAT 90
608608
#define TYPESTRICTROUNDING 91
609+
#define TYPECHOP 92
609610
#endif
610611

611612
/*

sources/proces.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3998,6 +3998,10 @@ SkipCount: level++;
39983998
AT.WorkPointer = term + *term;
39993999
if ( StrictRounding(BHEAD term,level,C->lhs[level][2],C->lhs[level][3]) ) goto GenCall;
40004000
goto Return0;
4001+
case TYPECHOP:
4002+
AT.WorkPointer = term + *term;
4003+
if ( Chop(BHEAD term,level) ) goto GenCall;
4004+
goto Return0;
40014005
#endif
40024006
}
40034007
goto SkipCount;

0 commit comments

Comments
 (0)