Florent Angly
2016-Dec-20 12:26 UTC
[Rd] Very small numbers in hexadecimal notation parsed as zero
Hi all, I have noticed incorrect parsing of very small hexadecimal numbers like "0x1.00000000d0000p-987". Such a hexadecimal representation can can be produced by sprintf() using the %a flag. The return value is incorrectly reported as 0 when coercing these numbers to double using as.double()/as.numeric(), as illustrated in the three examples below: as.double("0x1.00000000d0000p-987") # should be 7.645296e-298 as.double("0x1.0000000000000p-1022") # should be 2.225074e-308 as.double("0x1.f89fc1a6f6613p-974") # should be 1.23456e-293 The culprit seems to be the src/main/util.c:R_strtod function and in some cases, removing the zeroes directly before the 'p' leads to correct parsing: as.double("0x1.00000000dp-987") # 7.645296e-298, as expected as.double("0x1.p-1022") # 2.225074e-308, as expected I wrote a small program (in a file called "strtod.c") to compare the R stdtod implementation to a C implementation. The C implementation never reported 0 in the examples given above: #include <stdlib.h> #include <stdio.h> int main(void) { char *string, *stopstring; double x; string = "0x1.00000000d0000p-987"; x = strtod(string, &stopstring); printf("string = \"%s\"\n", string); printf("strtod = %.17g\n\n", x); string = "0x1.00000000dp-987"; x = strtod(string, &stopstring); printf("string = \"%s\"\n", string); printf("strtod = %.17g\n\n", x); } $ gcc -o strtod.exe strtod.c $ ./strtod.exe string = "0x1.00000000d0000p-987" strtod = 7.6452955642246671e-298 string = "0x1.00000000dp-987" strtod = 7.6452955642246671e-298 string = "0x1.0000000000000p-1022" strtod = 2.2250738585072014e-308 string = "0x1.p-1022" strtod = 2.2250738585072014e-308 string = "0x1.f89fc1a6f6613p-974" strtod = 1.23456e-293 My sessionInfo() returns: R version 3.3.2 (2016-10-31) Platform: x86_64-w64-mingw32/x64 (64-bit) Running under: Windows 7 x64 (build 7601) Service Pack 1 locale: [1] LC_COLLATE=German_Switzerland.1252 LC_CTYPE=German_Switzerland.1252 LC_MONETARY=German_Switzerland.1252 LC_NUMERIC=C LC_TIME=German_Switzerland.1252 attached base packages: [1] stats graphics grDevices utils datasets methods base Regards, Florent
Martin Maechler
2016-Dec-21 11:28 UTC
[Rd] Very small numbers in hexadecimal notation parsed as zero
>>>>> Florent Angly <florent.angly at gmail.com> >>>>> on Tue, 20 Dec 2016 13:26:36 +0100 writes:> Hi all, > I have noticed incorrect parsing of very small hexadecimal numbers > like "0x1.00000000d0000p-987". Such a hexadecimal representation can > can be produced by sprintf() using the %a flag. The return value is > incorrectly reported as 0 when coercing these numbers to double using > as.double()/as.numeric(), as illustrated in the three examples below: > as.double("0x1.00000000d0000p-987") # should be 7.645296e-298 > as.double("0x1.0000000000000p-1022") # should be 2.225074e-308 > as.double("0x1.f89fc1a6f6613p-974") # should be 1.23456e-293 > The culprit seems to be the src/main/util.c:R_strtod function and in > some cases, removing the zeroes directly before the 'p' leads to > correct parsing: > as.double("0x1.00000000dp-987") # 7.645296e-298, as expected > as.double("0x1.p-1022") # 2.225074e-308, as expected Yes, this looks like a bug, indeed. Similarly convincing is a simple comparison (of even less extreme)> as.double("0x1p-987")[1] 7.645296e-298> as.double("0x1.0000000000p-987")[1] 0>The "bug boundary" seems around here:> as.double("0x1.000000000000000000000000p-928") # fails[1] 0> as.double("0x1p-928")[1] 4.407213e-280>> as.double("0x1.000000000000000000000000p-927") # works[1] 8.814426e-280 but then adding more zeros before "p-927" also underflows. --> I have created an R bugzilla account for you; so you now can submit bug reports (including patch proposals to the source (hint!) ;-) Thank you, Florent! Martin
Florent Angly
2016-Dec-24 13:33 UTC
[Rd] Very small numbers in hexadecimal notation parsed as zero
Hi Martin, Thanks for the Bugzilla account. I have filed this bug under number 17199. Cheers, Florent On 21 December 2016 at 12:28, Martin Maechler <maechler at stat.math.ethz.ch> wrote:>>>>>> Florent Angly <florent.angly at gmail.com> >>>>>> on Tue, 20 Dec 2016 13:26:36 +0100 writes: > > > Hi all, > > I have noticed incorrect parsing of very small hexadecimal numbers > > like "0x1.00000000d0000p-987". Such a hexadecimal representation can > > can be produced by sprintf() using the %a flag. The return value is > > incorrectly reported as 0 when coercing these numbers to double using > > as.double()/as.numeric(), as illustrated in the three examples below: > > > as.double("0x1.00000000d0000p-987") # should be 7.645296e-298 > > as.double("0x1.0000000000000p-1022") # should be 2.225074e-308 > > as.double("0x1.f89fc1a6f6613p-974") # should be 1.23456e-293 > > > The culprit seems to be the src/main/util.c:R_strtod function and in > > some cases, removing the zeroes directly before the 'p' leads to > > correct parsing: > > > as.double("0x1.00000000dp-987") # 7.645296e-298, as expected > > as.double("0x1.p-1022") # 2.225074e-308, as expected > > Yes, this looks like a bug, indeed. > Similarly convincing is a simple comparison (of even less extreme) > >> as.double("0x1p-987") > [1] 7.645296e-298 >> as.double("0x1.0000000000p-987") > [1] 0 >> > > The "bug boundary" seems around here: > >> as.double("0x1.000000000000000000000000p-928") # fails > [1] 0 >> as.double("0x1p-928") > [1] 4.407213e-280 >> > >> as.double("0x1.000000000000000000000000p-927") # works > [1] 8.814426e-280 > > but then adding more zeros before "p-927" also underflows. > > --> I have created an R bugzilla account for you; so you now > can submit bug reports (including patch proposals to the source (hint!) ;-) > > Thank you, Florent! > Martin