@@ -902,10 +902,13 @@ UBYTE *CheckFloat(UBYTE *ss, int *spec)
902902 #[ Float Routines :
903903 #[ SetFloatPrecision :
904904
905- We set the default precision of the floats and allocate
906- space for an output string if we want to write the float.
907- Space needed: exponent: up to 12 chars.
908- mantissa 2+10*prec/33 + a little bit extra.
905+ Sets the default precision (in bits) of the floats and allocate
906+ buffer space for an output string.
907+ The buffer is used by PrintFloat (decimal output) and Strictrounding
908+ (binary or decimal output), so it must accommodate the larger space
909+ requirement:
910+ exponent: up to 12 chars.
911+ mantissa: prec + a little bit extra
909912*/
910913
911914int SetFloatPrecision (WORD prec )
@@ -917,7 +920,7 @@ int SetFloatPrecision(WORD prec)
917920 else {
918921 AC .DefaultPrecision = prec ;
919922 if ( AO .floatspace != 0 ) M_free (AO .floatspace ,"floatspace" );
920- AO .floatsize = (( 10 * prec )/ 33 + 20 )* sizeof (char );
923+ AO .floatsize = (prec + 20 )* sizeof (char );
921924 AO .floatspace = (UBYTE * )Malloc1 (AO .floatsize ,"floatspace" );
922925 mpf_set_default_prec (prec );
923926 return (0 );
@@ -1348,6 +1351,50 @@ int CoToRat(UBYTE *s)
13481351
13491352/*
13501353 #] CoToRat :
1354+ #[ CoStrictRounding :
1355+
1356+ Syntax: StrictRounding [precision][base]
1357+ - precision: number of digits to round to (optional)
1358+ - base: 'd' for decimal (base 10) or 'b' for binary (base 2)
1359+
1360+ If no arguments are provided, uses default precision with binary base.
1361+ */
1362+ int CoStrictRounding (UBYTE * s )
1363+ {
1364+ GETIDENTITY
1365+ WORD x ;
1366+ int base ;
1367+ if ( AT .aux_ == 0 ) {
1368+ MesPrint ("&Illegal attempt for strict rounding without activating floating point numbers." );
1369+ MesPrint ("&Forgotten %#startfloat instruction?" );
1370+ return (1 );
1371+ }
1372+ while ( * s == ' ' || * s == ',' || * s == '\t' ) s ++ ;
1373+ if ( * s == 0 ) {
1374+ /* No subkey, which means round to default precision */
1375+ x = AC .DefaultPrecision - AC .MaxWeight - 1 ;
1376+ Add4Com (TYPESTRICTROUNDING ,x ,2 );
1377+ return (0 );
1378+ }
1379+ if ( FG .cTable [* s ] == 1 ) { /* number */
1380+ ParseNumber (x ,s )
1381+ if ( tolower (* s ) == 'd' ) { base = 10 ; s ++ ; } /* decimal base */
1382+ else if ( tolower (* s ) == 'b' ){ base = 2 ; s ++ ; } /* binary base */
1383+ else goto IllPar ; /* invalid base specification */
1384+ }
1385+ while ( * s == ' ' || * s == ',' || * s == '\t' ) s ++ ;
1386+
1387+ /* Check for invalid arguments */
1388+ if ( * s ) {
1389+ IllPar :
1390+ MesPrint ("&Illegal argument(s) in StrictRounding statement: '%s'" ,s );
1391+ return (1 );
1392+ }
1393+ Add4Com (TYPESTRICTROUNDING ,x ,base );
1394+ return (0 );
1395+ }
1396+ /*
1397+ #] CoStrictRounding :
13511398 #[ ToFloat :
13521399
13531400 Converts the coefficient to floating point if it is still a rat.
@@ -1416,6 +1463,64 @@ int ToRat(PHEAD WORD *term, WORD level)
14161463
14171464/*
14181465 #] ToRat :
1466+ #[ StrictRounding :
1467+
1468+ Rounds floating point numbers to a specified precision
1469+ in a given base (decimal or binary).
1470+ */
1471+ int StrictRounding (PHEAD WORD * term , WORD level , WORD prec , WORD base ) {
1472+ WORD * t ,* tstop ;
1473+ int sign ,size ,maxprec = AC .DefaultPrecision - AC .MaxWeight - 1 ;
1474+ /* maxprec is in bits */
1475+ if ( base == 2 && prec > maxprec ) {
1476+ prec = maxprec ;
1477+ }
1478+ if ( base == 10 && prec > (int )(maxprec * log10 (2.0 )) ) {
1479+ prec = maxprec * log10 (2.0 );
1480+ }
1481+ /* Find the float which should be at the end. */
1482+ tstop = term + * term ; size = ABS (tstop [-1 ]);
1483+ sign = tstop [-1 ] < 0 ? -1 : 1 ; tstop -= size ;
1484+ t = term + 1 ;
1485+ while ( t < tstop ) {
1486+ if ( * t == FLOATFUN && t + t [1 ] == tstop && TestFloat (t ) &&
1487+ size == 3 && tstop [0 ] == 1 && tstop [1 ] == 1 ) {
1488+ break ;
1489+ }
1490+ t += t [1 ];
1491+ }
1492+ if ( t < tstop ) {
1493+ /*
1494+ Now t points at the float_ function and everything is correct.
1495+ The result can go straight over the float_ function.
1496+ */
1497+ char * s ;
1498+ mp_exp_t exp ;
1499+ /* Extract the floating point value */
1500+ UnpackFloat (aux4 ,t );
1501+ /* Convert to string:
1502+ - Format as MeN with M the mantissa and N the exponent
1503+ - the generated string by mpf_get_str is the fraction/mantissa with
1504+ an implicit radix point immediately to the left of the first digit.
1505+ The applicable exponent is written in exp. */
1506+ s = (char * )AO .floatspace ;
1507+ * s ++ = '.' ;
1508+ mpf_get_str (s ,& exp , base , prec , aux4 );
1509+ while ( * s != 0 ) s ++ ;
1510+ * s ++ = 'e' ;
1511+ snprintf (s ,AO .floatsize - (s - (char * )AO .floatspace ),"%ld" ,exp );
1512+ /* Negative base values are used to specify that the exponent is in decimal */
1513+ mpf_set_str (aux4 ,(char * )AO .floatspace ,- base );
1514+ /* Pack the rounded floating point value back into the term */
1515+ PackFloat (t ,aux4 );
1516+ t += t [1 ];
1517+ * t ++ = 1 ; * t ++ = 1 ; * t ++ = 3 * sign ;
1518+ * term = t - term ;
1519+ }
1520+ return (Generator (BHEAD term ,level )) ;
1521+ }
1522+ /*
1523+ #] StrictRounding :
14191524 #] Float Routines :
14201525 #[ Sorting :
14211526
0 commit comments