Skip to content

Commit d7fd2ec

Browse files
committed
FEAT: added support for loading NaN (1.#NaN) and Infinite (1.#INF) values and using them in decimal computations
This feature is optional and can be turned of by using USE_NO_INFINITY compilation define.
1 parent d5a978b commit d7fd2ec

File tree

5 files changed

+123
-3
lines changed

5 files changed

+123
-3
lines changed

make/make-settings.r

+1
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ Defines: [
1212
USE_PNG_CODEC
1313
USE_GIF_CODEC
1414
USE_JPG_CODEC
15+
;USE_NO_INFINITY ;-- use when you don't want to support IEEE infinity
1516
]

src/core/f-dtoa.c

+4-3
Original file line numberDiff line numberDiff line change
@@ -3761,12 +3761,13 @@ dtoa
37613761
#endif
37623762
{
37633763
/* Infinity or NaN */
3764-
*decpt = 9999;
3764+
*decpt = 1;
37653765
#ifdef IEEE_Arith
37663766
if (!word1(&u) && !(word0(&u) & 0xfffff))
3767-
return nrv_alloc("Infinity", rve, 8);
3767+
return nrv_alloc("1#INF", rve, 5);
37683768
#endif
3769-
return nrv_alloc("NaN", rve, 3);
3769+
*sign = 0; //pretend that all NaNs are positive
3770+
return nrv_alloc("1#NaN", rve, 5);
37703771
}
37713772
#endif
37723773
#ifdef IBM

src/core/l-scan.c

+19
Original file line numberDiff line numberDiff line change
@@ -957,6 +957,25 @@
957957
if (cp[0] == '2' && cp[1] == '#' && cp[2] == '{')
958958
{cp++; goto pound;} // very rare
959959
}
960+
961+
#ifndef USE_NO_INFINITY
962+
if (Skip_To_Char(cp, scan_state->end, 'x')) return TOKEN_PAIR;
963+
if (
964+
cp[0] == '1' && cp[1] == '.' && cp[2] == '#'
965+
) {
966+
if (( (cp[3] == 'I' || cp[3] == 'i')
967+
&& (cp[4] == 'N' || cp[4] == 'n')
968+
&& (cp[5] == 'F' || cp[5] == 'f')
969+
) || (
970+
(cp[3] == 'N' || cp[3] == 'n')
971+
&& (cp[4] == 'a' || cp[4] == 'A')
972+
&& (cp[5] == 'N' || cp[5] == 'n')
973+
)) {
974+
return TOKEN_DECIMAL;
975+
}
976+
}
977+
#endif // !USE_NO_INFINITY
978+
960979
return -TOKEN_INTEGER;
961980
}
962981
if (HAS_LEX_FLAG(flags, LEX_SPECIAL_COLON)) return TOKEN_TIME; /* 12:34 */

src/core/l-types.c

+91
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,43 @@ bad_hex: Trap0(RE_INVALID_CHARS);
260260
else cp++;
261261
if (*cp == ',' || *cp == '.') cp++;
262262
*ep++ = '.';
263+
264+
#ifndef USE_NO_INFINITY
265+
if (cp[0] == '#') {
266+
if (
267+
(cp[1] == 'I' || cp[1] == 'i')
268+
&& (cp[2] == 'N' || cp[2] == 'n')
269+
&& (cp[3] == 'F' || cp[3] == 'f')
270+
) {
271+
cp += 4;
272+
if ((REBCNT)(cp - bp) != len) return 0;
273+
VAL_SET(value, REB_DECIMAL);
274+
VAL_DECIMAL(value) = (bp[0] == '-') ? -INFINITY : INFINITY;
275+
return cp;
276+
}
277+
if (
278+
(cp[1] == 'N' || cp[1] == 'n')
279+
&& (cp[2] == 'a' || cp[2] == 'A')
280+
&& (cp[3] == 'N' || cp[3] == 'n')
281+
) {
282+
cp += 4;
283+
if ((REBCNT)(cp - bp) != len) return 0;
284+
VAL_SET(value, REB_DECIMAL);
285+
286+
// NOTE: NAN sign may differ!
287+
// VS (17) is producing negative NaN #{FFF8000000000000}, while GCC positive #{7FF8000000000000}!
288+
// Is this an issue?
289+
#if _MSC_VER
290+
VAL_DECIMAL(value) = (bp[0] == '-') ? NAN : -NAN;
291+
#else
292+
VAL_DECIMAL(value) = (bp[0] == '-') ? -NAN : NAN;
293+
#endif
294+
return cp;
295+
}
296+
return 0;
297+
}
298+
#endif // !USE_NO_INFINITY
299+
263300
while (IS_LEX_NUMBER(*cp) || *cp == '\'')
264301
if (*cp != '\'') *ep++ = *cp++, dig=1;
265302
else cp++;
@@ -745,13 +782,67 @@ bad_hex: Trap0(RE_INVALID_CHARS);
745782
//ep = Grab_Int(ep, &n);
746783
ep = Scan_Dec_Buf(cp, MAX_NUM_LEN, &buf[0]);
747784
if (!ep) return 0;
785+
786+
#ifndef USE_NO_INFINITY
787+
if (ep[0] == '#') {
788+
if (!((buf[0] == '-' && buf[1] == '1' && buf[2] == '.') || (buf[0] == '1' && buf[1] == '.'))) return 0; //don't allow numbers like 20.#INF or -2.#INF
789+
if (
790+
(ep[1] == 'I' || ep[1] == 'i') &&
791+
(ep[2] == 'N' || ep[2] == 'n') &&
792+
(ep[3] == 'F' || ep[3] == 'f')
793+
) {
794+
VAL_PAIR_X(value) = buf[0] == '-' ? -INFINITY : INFINITY;
795+
ep += 4;
796+
}
797+
else if (
798+
(ep[1] == 'N' || ep[1] == 'n')
799+
&& (ep[2] == 'a' || ep[2] == 'A')
800+
&& (ep[3] == 'N' || ep[3] == 'n')
801+
) {
802+
ep += 4;
803+
VAL_PAIR_X(value) = NAN;
804+
}
805+
else return 0;
806+
} else {
807+
VAL_PAIR_X(value) = (float)atof((char*)(&buf[0])); //n;
808+
}
809+
#else
748810
VAL_PAIR_X(value) = (float)atof((char*)(&buf[0])); //n;
811+
#endif // !USE_NO_INFINITY
812+
749813
if (*ep != 'x' && *ep != 'X') return 0;
750814
ep++;
751815

752816
xp = Scan_Dec_Buf(ep, MAX_NUM_LEN, &buf[0]);
753817
if (!xp) return 0;
818+
819+
#ifndef USE_NO_INFINITY
820+
if (xp[0] == '#') {
821+
if(!((buf[0]=='-' && buf[1]=='1' && buf[2]=='.') || (buf[0]=='1' && buf[1]=='.'))) return 0; //don't allow numbers like 20.#INF or -2.#INF
822+
if (
823+
(xp[1] == 'I' || xp[1] == 'i') &&
824+
(xp[2] == 'N' || xp[2] == 'n') &&
825+
(xp[3] == 'F' || xp[3] == 'f')
826+
) {
827+
VAL_PAIR_Y(value) = buf[0] == '-' ? -INFINITY : INFINITY;
828+
xp += 4;
829+
}
830+
else if (
831+
(xp[1] == 'N' || xp[1] == 'n')
832+
&& (xp[2] == 'a' || xp[2] == 'A')
833+
&& (xp[3] == 'N' || xp[3] == 'n')
834+
) {
835+
xp += 4;
836+
VAL_PAIR_Y(value) = NAN;
837+
}
838+
else return 0;
839+
}
840+
else {
841+
VAL_PAIR_Y(value) = (float)atof((char*)(&buf[0])); //n;
842+
}
843+
#else
754844
VAL_PAIR_Y(value) = (float)atof((char*)(&buf[0])); //n;
845+
#endif // !USE_NO_INFINITY
755846

756847
if (len > (REBCNT)(xp - cp)) return 0;
757848
VAL_SET(value, REB_PAIR);

src/core/t-decimal.c

+8
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ REBOOL almost_equal(REBDEC a, REBDEC b, REBCNT max_diff) {
9595
union {REBDEC d; REBI64 i;} ua, ub;
9696
REBI64 int_diff;
9797

98+
#ifndef USE_NO_INFINITY
99+
if(isnan(a) || isnan(b)) return FALSE;
100+
#endif // !USE_NO_INFINITY
101+
98102
ua.d = a;
99103
ub.d = b;
100104

@@ -287,7 +291,9 @@ REBOOL almost_equal(REBDEC a, REBDEC b, REBCNT max_diff) {
287291

288292
case A_DIVIDE:
289293
case A_REMAINDER:
294+
#ifdef USE_NO_INFINITY
290295
if (d2 == 0.0) Trap0(RE_ZERO_DIVIDE);
296+
#endif
291297
if (action == A_DIVIDE) d1 /= d2;
292298
else d1 = fmod(d1, d2);
293299
goto setDec;
@@ -460,7 +466,9 @@ REBOOL almost_equal(REBDEC a, REBDEC b, REBCNT max_diff) {
460466
Trap_Action(VAL_TYPE(val), action);
461467

462468
setDec:
469+
#ifdef USE_NO_INFINITY
463470
if (!FINITE(d1)) Trap0(RE_OVERFLOW);
471+
#endif
464472
#ifdef not_required
465473
if (type == REB_PERCENT) {
466474
// Keep percent in smaller range (not to use e notation).

0 commit comments

Comments
 (0)