Bug 17199 - Very small numbers in hexadecimal notation parsed as zero
Summary: Very small numbers in hexadecimal notation parsed as zero
Status: CLOSED FIXED
Alias: None
Product: R
Classification: Unclassified
Component: Low-level (show other bugs)
Version: R 3.3.0
Hardware: x86_64/x64/amd64 (64-bit) Windows 64-bit
: P5 normal
Assignee: R-core
URL:
Depends on:
Blocks:
 
Reported: 2016-12-24 13:32 UTC by Florent Angly
Modified: 2017-01-08 12:39 UTC (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Florent Angly 2016-12-24 13:32:17 UTC
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 


Original R-devel mailing list report and discussion available from 
http://r.789695.n4.nabble.com/Very-small-numbers-in-hexadecimal-notation-parsed-as-zero-td4727525.html
Comment 1 Duncan Murdoch 2017-01-08 12:39:17 UTC
The problem is that on systems where long double is the same as double, an intermediate value overflowed.  I have a fix now, and will commit it to R-devel and R-patched after some testing.