There are lots of cases where strtoflt128() is not assigning subnormal values correctly - and the error can be far more than just a few ULPs.
The values that are causing the problems, seem to fall into 3 categories:
1) strings of the form D.dd...e-4951 where "D" is either "1", "2", or "3" (eg "1.864043e-4951", "2.819208e-4951" and "3.58e-4951");
2) strings of the form 1.dd...e-4941 (eg "1.242435e-4941");
3) strings of the form D.dd...e-4942 where "D" is either "8" or "9" (eg "8.176823e-4942", "9.74e-4942").
I don't mean that every string that fits one of those categories will inevitably be assigned incorrectly - it's just that the values I've found to be miscalculated always fit one of those categories.
For example, I find 3.08e-4951, 3.18e-4951, 3.28e-4951, 3.38e-4951, 3.48e-4951 and 3.58e-4951 are assigned incorrectly, but 3.68e-4951 is assigned correctly.
No such problem on Ubuntu - it's just the Windows strtoflt128() calculation that can be inaccurate.
(On Windows, I have a range of mingw compilers from 4.7.0 through to 7.2.0, and the behaviour is the same for all of them.
On Ubuntu, I have only gcc-5.4.0.)
Attached is the C program that demonstrates the anomalies for 2 specific values.
It firstly calculates 3.58e-4951 as:
f1 = strtoflt128("3.58e-4951", NULL);
and then as
f2 = 358 * (5 ^ -4953) * (2 ^ -4953);
f1 and f2 should be equivalent but the significands are quite different on Windows, where:
f1 = 3.58000000021311022967612420460407998e-4951
= 0x0.0000000000000001f6d797affeffp-16382
f2 = 3.57999999999999926614517992215333485e-4951
= 0x0.0000000000000001f6d797af7e6fp-16382
On Ubuntu, f1 and f2 have the same value:
f1 = 3.57999999999999926614517992215333485e-4951
= 0x0.0000000000000001f6d797af7e6fp-16382
f2 = 3.57999999999999926614517992215333485e-4951
= 0x0.0000000000000001f6d797af7e6fp-16382
and I've confirmed that the Ubuntu result is correct, according to mpfr-4.0.
Next, the C program calculates (using the same approaches) 9.74e-4942:
f1 = strtoflt128("9.74e-4942", NULL);
f2 = 974 * (5 ^ -4944) * (2 ^ -4944);
Again, Windows produces conflicting results:
f1 = 9.74000000200773726651588279988191118e-4942
= 0x0.000000013e87318d3ff77faea7fep-16382
f2 = 9.73999999999999999999999693066104753e-4942
= 0x0.000000013e87318c25f66e2e8318p-16382
and Ubuntu produces correct results:
f1 = 9.73999999999999999999999693066104753e-4942
= 0x0.000000013e87318c25f66e2e8318p-16382
f2 = 9.73999999999999999999999693066104753e-4942
= 0x0.000000013e87318c25f66e2e8318p-16382
Cheers,
Rob
I've found that the affected subnormals are all either in the range 1.8226001020320419902366105930885830e-4951 to 3.6451995318824681273532864955943088e-4951 (0x1.00000318p-16446 to 0x1.ffffffffffffp-16446), or in the range 7.8280063884148688667050511979538776e-4942 to 1.5656012776829737733410095920732635e-4941 (0x1p-16414 to 0x1.ffffffffffffffffffffp-16414).
I've checked thousands of random values inside both ranges and, for the former range, I'm finding that only approximately 0.5% of those values are being assigned correctly.
For the latter range, all of the values I've tested have been assigned incorrectly.
I haven't struck any problem with values that fall outside of those 2 ranges.
Cheers,
Rob
Apparently this is a gcc libquadmath bug, and nothing to do with mingw-w64.
(I'll therefore close this report if I can wotk out how to.)
I have lodged a bug report about this issue with gcc's bugzilla at:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94756
Cheers,
Rob