Skip to content

Commit e3eeea3

Browse files
committed
feat: #startfloat and Format floatprecision syntax
- #StartFloat <precision>(b/d), MZV = <weight>, with precision either in bits (b) or digits (d). - Format floatprecision <precision>(b/d). fix: PrintFloat - PrintFloat returns correct number of characters and proper Mathematica format - Trailing zeroes in floats are also removed when precision set by Format floatprecision is less then precision of #startfloat. test: updated and expanded float tests for new syntax doc: updated manual for #StartFloat syntax and added entries/documentation for #startfloat, #endfloat, evaluate, tofloat, torational and format floatprecision.
1 parent e8602de commit e3eeea3

File tree

9 files changed

+574
-74
lines changed

9 files changed

+574
-74
lines changed

check/features.frm

Lines changed: 410 additions & 51 deletions
Large diffs are not rendered by default.

check/fixes.frm

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3926,7 +3926,7 @@ assert succeeded?
39263926
assert result("F") =~ expr("0")
39273927
*--#] Issue642 :
39283928
*--#[ Issue646 :
3929-
#StartFloat 30
3929+
#StartFloat 9d
39303930
Local F = mzv_+euler_+mzvhalf_;
39313931
Evaluate;
39323932
Print;
@@ -3937,14 +3937,14 @@ assert result("F") =~ expr("mzv_ + euler_ + mzvhalf_")
39373937
*--#] Issue646 :
39383938
*--#[ Issue664 :
39393939
#-
3940-
#StartFloat 64
3940+
#StartFloat 64b
39413941
Evaluate 1;
39423942
.end
39433943
#pend_if wordsize == 2
39443944
assert compile_error?("should be a built in function that can be evaluated numerically.")
39453945
*--#] Issue664 :
39463946
*--#[ Issue695_1 :
3947-
#StartFloat 20
3947+
#StartFloat 20b
39483948
CFunction f;
39493949
Local F1 = f(1.0)+f(1.0);
39503950
Local F2 = f(1.0)/3+f(1.0)*2.0;
@@ -3962,7 +3962,7 @@ assert result("F4") =~ expr("f(1.0e+00) + f(1.1e+00)")
39623962
assert result("F5") =~ expr("f(1/2) + f(5.0e-01)")
39633963
*--#] Issue695_1 :
39643964
*--#[ Issue695_2 :
3965-
#StartFloat 30
3965+
#StartFloat 9d
39663966
Symbol a,b;
39673967
CFunction f;
39683968
Local F = 1.0*f(a);

doc/manual/float.tex

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ \chapter{Floating point}
33
\label{floatingpoint}
44

55
Starting with version 5.0 \FORM\ is equiped with arbitrary floating point
6-
capacity. The low level routines are part of the GMP and mpfr libraries
6+
capability. The low level routines are part of the GMP and mpfr libraries
77
which should be available on most systems. If not they can be picked up
88
easily from the internet. The main commands involving the floating point
99
system are
@@ -12,11 +12,13 @@ \chapter{Floating point}
1212
point system. Invoking it will allocate a number of arrays. The instruction
1313
has either one or two arguments:
1414
\begin{verbatim}
15-
#startfloat numberofbits <,maximumweight>
15+
#startfloat <precision> [,MZV=<maximumweight>]
1616
\end{verbatim}
17-
The first argument is mandatory. It tells how many bits of accuracy are
18-
required. \FORM{} will round to at least this precision. Because the internal
19-
routines work with WORDs the precision will be rounded up to the nearest
17+
The first argument is mandatory and specifies the desired precision. It must
18+
be a positive integer followed by either \texttt{b} (for precision in bits)
19+
or \texttt{d} (for precision in decimal digits).
20+
\FORM{} will round to at least this precision. Because the internal
21+
routines work with WORDs, the precision (in bits) will internally be rounded up to the nearest
2022
integer number of WORDs. The second argument is optional for when one wants
2123
to work with multiple zeta values (MZVs) or Euler sums. It specifies the
2224
maximum weight that will be used. The evaluation of the sums requires a
@@ -49,6 +51,27 @@ \chapter{Floating point}
4951
arguments are the functions mzv\_, euler\_, sqrt\_ and mzvhalf\_. If any
5052
(or more than one) of these are specified only those functions will be
5153
evaluated.
54+
\item[Format floatprecision] This instruction controls how many digits are
55+
displayed when printing floating point numbers. It only affects output
56+
formatting and does not influence the internal precision or accuracy of
57+
computations. It can be used in three ways: in case of
58+
\begin{verbatim}
59+
Format floatprecision;
60+
\end{verbatim}
61+
\FORM{} prints floats with the number of digits specified by the current
62+
\#startfloat instruction. With
63+
\begin{verbatim}
64+
Format floatprecision <precision>;
65+
\end{verbatim}
66+
\FORM{} prints the number of digits specified by \texttt{<precision>}.
67+
The syntax is the same as for the precision in \#startfloat: a positive
68+
integer followed by either \texttt{b} (for bits) or \texttt{d} (for decimal
69+
digits). If the requested precision exceeds the precision specified by
70+
\#startfloat, only the available digits are printed. Finally, with
71+
\begin{verbatim}
72+
Format floatprecision off;
73+
\end{verbatim}
74+
the floating point numbers are printed in raw internal format.
5275
\end{description}
5376
In addition to the above commands there are the following functions that
5477
can be evaluated sqrt\_, ln\_, li2\_, gamma\_, agm\_, sin\_, cos\_, tan\_,
@@ -65,7 +88,7 @@ \chapter{Floating point}
6588

6689
The following example shows some work with Multiple Zeta Values (MZV's):
6790
\begin{verbatim}
68-
#StartFloat 500,15
91+
#StartFloat 500b, MZV=15
6992
L F1 =
7093
-mzv_(8,1,1,5)
7194
+29056868/39414375*mzv_(2)^6*mzv_(3)

doc/manual/prepro.tex

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -935,6 +935,18 @@ \section{\#enddo}
935935
do\index{do loop} loop. See the \#do\index{\#do} instruction.
936936

937937
%--#] enddo :
938+
%--#[ endfloat :
939+
940+
\section{\#endfloat}
941+
\label{preendfloat}
942+
943+
\noindent Syntax:
944+
945+
\#endfloat
946+
947+
\noindent See also startfloat (\ref{prestartfloat}) and chapter~\ref{floatingpoint} on the floating point capability.
948+
949+
%--#] endfloat :
938950
%--#[ endif :
939951

940952
\section{\#endif}
@@ -1960,6 +1972,18 @@ \section{\#sortreallocate}
19601972
\FORM's memory usage as measured by ``resident set size''.
19611973

19621974
%--#] sortreallocate :
1975+
%--#[ startfloat :
1976+
1977+
\section{\#startfloat}
1978+
\label{prestartfloat}
1979+
1980+
\noindent Syntax:
1981+
1982+
\#startfloat $<$precision$>$ [,MZV=$<$weight$>$]
1983+
1984+
\noindent See also endfloat (\ref{preendfloat}) and chapter~\ref{floatingpoint} on the floating point capability.
1985+
1986+
%--#] startfloat :
19631987
%--#[ switch :
19641988

19651989
\section{\#switch}

doc/manual/statements.tex

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1478,6 +1478,18 @@ \section{endwhile}
14781478
module. \vspace{10mm}
14791479

14801480
%--#] endwhile :
1481+
%--#[ evaluate :
1482+
\section{evaluate}
1483+
\label{substaevaluate}
1484+
1485+
\noindent \begin{tabular}{ll}
1486+
Type & Executable statement\\
1487+
Syntax & evaluate [$<$function name$>$]; \\
1488+
\end{tabular} \vspace{4mm}
1489+
1490+
\noindent See chapter~\ref{floatingpoint} on the floating point capability.
1491+
1492+
%--#] evaluate :
14811493
%--#[ exit :
14821494

14831495
\section{exit}
@@ -1902,6 +1914,9 @@ \section{format}
19021914
\rightvitem{13cm}{Output format is switched back to rational numbers (in
19031915
contrast to floating point output). This is the default.}
19041916

1917+
\leftvitem{3.5cm}{floatprecision\index{floatprecision}\index{format!floatprecision} \hfill \\ \null{\tt[}$<$off$>\!|\!<$number$>${\tt]}}
1918+
\rightvitem{13cm}{See chapter~\ref{floatingpoint} on the floating point capability.}
1919+
19051920
\leftvitem{3.5cm}{nospaces\index{nospaces}\index{format!nospaces}}
19061921
\rightvitem{13cm}{The output is printed without the spaces that make the
19071922
output slightly more readable. This gives a more compact output.}
@@ -5876,6 +5891,18 @@ \section{threadbucketsize}
58765891
`ON,setup;' statement (\ref{substaon} and \ref{setup}). \vspace{10mm}
58775892

58785893
%--#] threadbucketsize :
5894+
%--#[ tofloat :
5895+
\section{tofloat}
5896+
\label{substatofloat}
5897+
5898+
\noindent \begin{tabular}{ll}
5899+
Type & Executable statement\\
5900+
Syntax & tofloat;
5901+
\end{tabular} \vspace{4mm}
5902+
5903+
\noindent See chapter~\ref{floatingpoint} on the floating point capability.
5904+
5905+
%--#] tofloat :
58795906
%--#[ topolynomial :
58805907

58815908
\section{topolynomial}
@@ -5909,6 +5936,18 @@ \section{topolynomial}
59095936
\vspace{10mm}
59105937

59115938
%--#] topolynomial :
5939+
%--#[ torational :
5940+
\section{torational}
5941+
\label{substatorational}
5942+
5943+
\noindent \begin{tabular}{ll}
5944+
Type & Executable statement\\
5945+
Syntax & torational;
5946+
\end{tabular} \vspace{4mm}
5947+
5948+
\noindent See chapter~\ref{floatingpoint} on the floating point capability.
5949+
5950+
%--#] torational :
59125951
%--#[ tospectator :
59135952

59145953
\section{tospectator}

sources/compcomm.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "comtool.h"
4242
#ifdef WITHFLOAT
4343
#include <gmp.h>
44+
#include <math.h>
4445
#endif
4546

4647
static KEYWORD formatoptions[] = {
@@ -394,6 +395,13 @@ int CoFormat(UBYTE *s)
394395
while ( *s <= '9' && *s >= '0' )
395396
AO.FloatPrec = 10*AO.FloatPrec + (*s++ - '0');
396397
while ( *s == ' ' || *s == '\t' || *s == ',' ) s++;
398+
/*
399+
The precision can either be in digits or bits.
400+
AO.FloatPrec is in digits.
401+
*/
402+
if ( tolower(*s) == 'd' ) { s++; }
403+
else if ( tolower(*s) == 'b' ) { AO.FloatPrec = AO.FloatPrec*log10(2.0); s++; }
404+
else { s = ss; goto WrongOption; }
397405
if ( *s ) { s = ss; goto WrongOption; }
398406
}
399407
else {

sources/float.c

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -934,12 +934,13 @@ int SetFloatPrecision(WORD prec)
934934
regular Form function and it should never come here because the
935935
print routines in sch.c should intercept it.
936936
The buffer AO.floatspace is allocated when the precision of the
937-
floats is set in the routine SetupMZVTables.
937+
floats is set in the routine SetFloatPrecision.
938938
*/
939939

940940
int PrintFloat(WORD *fun,int numdigits)
941941
{
942942
GETIDENTITY
943+
UBYTE *s1, *s2;
943944
int n = 0;
944945
int prec = (AC.DefaultPrecision-AC.MaxWeight-1)*log10(2.0);
945946
if ( numdigits > prec || numdigits == 0 ) {
@@ -951,8 +952,7 @@ int PrintFloat(WORD *fun,int numdigits)
951952
*/
952953
if ( UnpackFloat(aux4,fun) == 0 )
953954
n = gmp_snprintf((char *)(AO.floatspace),AO.floatsize,"%.*Fe",numdigits-1,aux4);
954-
if ( numdigits == prec ) {
955-
UBYTE *s1, *s2;
955+
if ( n > 0 ) {
956956
int n1, n2 = n;
957957
s1 = AO.floatspace+n;
958958
while ( s1 > AO.floatspace && s1[-1] != 'e'
@@ -962,10 +962,28 @@ int PrintFloat(WORD *fun,int numdigits)
962962
s2 = s1; n1 = n2;
963963
while ( s1[-1] == '0' ) { s1--; n1--; }
964964
if ( s1[-1] == '.' ) { s1++; n1++; }
965-
while ( n2 < n ) { *s1++ = *s2++; n2++; }
966965
n -= (n2-n1);
966+
while ( n1 < n ) { *s1++ = *s2++; n1++; }
967967
*s1 = 0;
968968
}
969+
if ( AC.OutputMode == FORTRANMODE ) {
970+
s1 = AO.floatspace+n;
971+
while ( s1 > AO.floatspace && *s1 != 'e' && *s1 != 'E' ) {
972+
s1--;
973+
}
974+
if ( ( AO.DoubleFlag & 2 ) == 2 ) { *s1 = 'Q'; } /* Quadruple precision fortran */
975+
else if ( ( AO.DoubleFlag & 1 ) == 1 ) { *s1 = 'D'; } /* Double precision fortran */
976+
else { *s1 = 'E'; } /* Single precision fortran */
977+
}
978+
if ( AC.OutputMode == MATHEMATICAMODE ) {
979+
s1 = AO.floatspace+n;
980+
s2 = s1+2; *s2-- = 0;
981+
while ( s1 > AO.floatspace && *s1 != 'e' && *s1 != 'E' ) {
982+
*s2-- = *s1--;
983+
}
984+
*s2-- = '^'; *s2 = '*'; /* Replace 'e' by '^*' */
985+
n++;
986+
}
969987
}
970988
return(n);
971989
}

sources/pre.c

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
#[ Includes :
3333
*/
3434
#include "form3.h"
35+
#ifdef WITHFLOAT
36+
#include "math.h"
37+
#endif
3538

3639
static UBYTE pushbackchar = 0;
3740
static int oldmode = 0;
@@ -7680,6 +7683,7 @@ int DoStartFloat(UBYTE *s)
76807683
GETIDENTITY
76817684
int error = 0;
76827685
LONG x;
7686+
UBYTE *ss;
76837687
if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
76847688
if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
76857689
if ( AR.PolyFun != 0 ) {
@@ -7691,20 +7695,42 @@ int DoStartFloat(UBYTE *s)
76917695
error = 1;
76927696
}
76937697
while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
7698+
/*
7699+
The first parameter is the float precision
7700+
*/
7701+
ss = s;
76947702
if ( *s >= '0' && *s <= '9' ) {
76957703
x = 0;
76967704
do {
76977705
x = 10*x + (*s++-'0');
76987706
} while ( *s >= '0' && *s <= '9' );
7699-
AC.tDefaultPrecision = x;
7707+
/*
7708+
The precision can either be in digits or bits.
7709+
AC.DefaultPrecision is always in bits.
7710+
*/
7711+
if ( tolower(*s) == 'd' ) { AC.tDefaultPrecision = (LONG)ceil(x*log2(10.0)); s++; }
7712+
else if ( tolower(*s) == 'b' ) { AC.tDefaultPrecision = x; s++; }
7713+
else goto IllPar;
77007714
while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
7701-
if ( *s >= '0' && *s <= '9' ) {
7702-
x = 0;
7703-
do {
7704-
x = 10*x + (*s++ - '0');
7705-
} while ( *s >= '0' && *s <= '9' );
7706-
AC.tMaxWeight = x;
7707-
while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
7715+
/*
7716+
The second parameter is either absent, which implies zero MZV weight,
7717+
or of the form MZV = <weight>
7718+
*/
7719+
if ( tolower(*s) == 'm' && tolower(s[1]) == 'z' && tolower(s[2]) == 'v') {
7720+
s+=3;
7721+
while ( *s == ' ' || *s == '\t' ) s++;
7722+
if ( *s != '=') goto IllPar;
7723+
s++;
7724+
while ( *s == ' ' || *s == '\t' ) s++;
7725+
if ( *s >= '0' && *s <= '9' ) {
7726+
x = 0;
7727+
do {
7728+
x = 10*x + (*s++ - '0');
7729+
} while ( *s >= '0' && *s <= '9' );
7730+
AC.tMaxWeight = x;
7731+
while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
7732+
}
7733+
else goto IllPar;
77087734
}
77097735
else {
77107736
AC.tMaxWeight = 0;
@@ -7713,7 +7739,7 @@ int DoStartFloat(UBYTE *s)
77137739
}
77147740
else if ( *s != 0 ) {
77157741
IllPar:
7716-
MesPrint("@Illegal parameter in %#StartFloat instruction: %s ",s);
7742+
MesPrint("@Illegal parameter in %#StartFloat: %s ",ss);
77177743
error = 1;
77187744
}
77197745
if ( error == 0 ) {

sources/sch.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2019,6 +2019,9 @@ int WriteInnerTerm(WORD *term, WORD first)
20192019
if ( *ss == FLOATFUN ) {
20202020
if ( ( FloatChars = PrintFloat(ss,AO.FloatPrec) ) != 0 ) {
20212021
TokenToLine(AO.floatspace);
2022+
if ( AC.IsFortran90 == ISFORTRAN90 && AC.Fortran90Kind ) {
2023+
AddToLine(AC.Fortran90Kind);
2024+
}
20222025
first = 0;
20232026
}
20242027
break;

0 commit comments

Comments
 (0)