Skip to content

Commit 02480bf

Browse files
committed
[42d14c495a] Parsing long floating point strings
2 parents 3dbcc28 + ea6c1b6 commit 02480bf

File tree

2 files changed

+80
-0
lines changed

2 files changed

+80
-0
lines changed

generic/tclStrToD.c

+34
Original file line numberDiff line numberDiff line change
@@ -1822,6 +1822,8 @@ MakeHighPrecisionDouble(
18221822
TCL_IEEE_DOUBLE_ROUNDING_DECL
18231823

18241824
int machexp = 0; /* Machine exponent of a power of 10. */
1825+
int shift, n;
1826+
mp_int bntmp;
18251827

18261828
/*
18271829
* With gcc on x86, the floating point rounding mode is double-extended.
@@ -1869,6 +1871,35 @@ MakeHighPrecisionDouble(
18691871
* for overflow. Convert back to a double, and test for underflow.
18701872
*/
18711873

1874+
/*
1875+
* TCL bug ca62367d61: the following two if-conditions handle the case,
1876+
* if the mantissa is to long to be represented.
1877+
* Very high numbers are returned, if this is not handled
1878+
*/
1879+
1880+
1881+
if (exponent < -511) {
1882+
mp_init_copy(&bntmp, significand);
1883+
shift = -exponent - 511;
1884+
exponent += shift;
1885+
while (shift > 0) {
1886+
n = (shift > 9) ? 9 : shift;
1887+
mp_div_d(&bntmp, (mp_digit) pow10_wide[n], &bntmp, NULL);
1888+
shift -= n;
1889+
}
1890+
significand = &bntmp;
1891+
} else if (exponent > 511) {
1892+
mp_init_copy(&bntmp, significand);
1893+
shift = exponent - 511;
1894+
exponent -= shift;
1895+
while (shift > 0) {
1896+
n = (shift > 9) ? 9 : shift;
1897+
mp_mul_d(&bntmp, (mp_digit) pow10_wide[n], &bntmp);
1898+
shift -= n;
1899+
}
1900+
significand = &bntmp;
1901+
}
1902+
18721903
retval = BignumToBiasedFrExp(significand, &machexp);
18731904
retval = Pow10TimesFrExp(exponent, retval, &machexp);
18741905
if (machexp > DBL_MAX_EXP*log2FLT_RADIX) {
@@ -1896,6 +1927,9 @@ MakeHighPrecisionDouble(
18961927
*/
18971928

18981929
returnValue:
1930+
if (significand == &bntmp) {
1931+
mp_clear(&bntmp);
1932+
}
18991933
if (signum) {
19001934
retval = -retval;
19011935
}

tests/scan.test

+46
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,52 @@ test scan-14.2 {negative infinity} {
880880
return $d
881881
} -Inf
882882

883+
test scan-15.1 {scan %g overflow for small numbers and big mantissa bug 42d14c495a} {
884+
set result [list]
885+
# xfail: n<num> = not expected at all, x<num> expected when unfixed
886+
foreach {exp numdig ret xfail} {
887+
-321 190 1.111647703142804724397279783953498087821e-321 n0
888+
-321 191 1.111647703142804724397279783953498087821e-321 x1
889+
-321 300 1.111647703142804724397279783953498087821e-321 x2
890+
-321 1600 1.111647703142804724397279783953498087821e-321 x3
891+
-400 110 0 n4
892+
-400 111 0 n5
893+
-400 300 0 n6
894+
-221 290 1.111111111111110993454921768172890541494e-221 n7
895+
-221 291 1.111111111111110993454921768172890541494e-221 x8
896+
-221 400 1.111111111111110993454921768172890541494e-221 x9
897+
-221 1600 1.111111111111110993454921768172890541494e-221 x10
898+
-121 390 1.111111111111111182884141698869046969295e-121 n11
899+
-121 391 1.111111111111111182884141698869046969295e-121 x12
900+
-121 500 1.111111111111111182884141698869046969295e-121 x13
901+
-121 1600 1.111111111111111182884141698869046969295e-121 x14
902+
308 202 1.111111111111111167662077577927612945036e+308 n15
903+
308 203 1.111111111111111167662077577927612945036e+308 n16
904+
308 300 1.111111111111111167662077577927612945036e+308 n17
905+
308 1600 1.111111111111111167662077577927612945036e+308 x18
906+
400 110 inf n19
907+
400 111 inf n20
908+
400 300 inf n21
909+
221 291 1.111111111111111207481621395250718679869e+221 n22
910+
221 292 1.111111111111111207481621395250718679869e+221 n23
911+
221 400 1.111111111111111207481621395250718679869e+221 n24
912+
221 1600 1.111111111111111207481621395250718679869e+221 x25
913+
121 391 1.11111111111111112711771954138363761759e+121 n26
914+
121 392 1.11111111111111112711771954138363761759e+121 n27
915+
121 500 1.11111111111111112711771954138363761759e+121 n28
916+
121 1600 1.11111111111111112711771954138363761759e+121 x29
917+
} {
918+
set s 1.[string repeat 1 $numdig]e$exp
919+
set d "no_scan"
920+
scan $s %g d
921+
set r [format %.40g $d]
922+
if {$r ne $ret} {
923+
lappend result $xfail=[format %.40g $d]
924+
}
925+
}
926+
set result
927+
} {}
928+
883929
# TODO - also need to scan NaN's
884930

885931
catch {rename int_range {}}

0 commit comments

Comments
 (0)