GNOME Bugzilla – Bug 588997
DEC2HEX and friends fail with large numbers.
Last modified: 2009-07-27 17:09:31 UTC
1609950720 1609950975 5FF5E600 5FF5E6FF 2034213780 2034213783 793FA394 793FA397 2147942400 2148007935 7FFFFFFF 7FFFFFFF 2159017984 2159083519 7FFFFFFF 7FFFFFFF Why can't I convert the two last numbers into hex? Thanks Grincheux http://asm39.com
Probably because the largest integer on your platform is 2147483647 (largest 32 bits signed integer). It would work on a 64 bits architecture (it does work with my amd64).
That means that Gnumeric is working on signed numbers, otherwise the problem would not exist. Thanks.
Hmm, not sure, this is a bug. it should work up to 549755813887 (20 bits integer) and return an error otherwise. Strangely, for this value gnumeric returns 7DABF41BFF whild gcalctool gives 7FFFFFFFFF.
Not 20 bits, 40 bits (guessing this comes from the C double type).
Looks like the issue comes from the limits used in all our conversion functions. These limits are evaluated so that the output will not exceed 10 digits, but the source code is written so as it is the source which should be limited to 10 digits (or I'm missing something). Setting the maximum to 9999999999 in dec2hex makes things work (also, the N complement code should not be applied to base 10). But what I describe is NOT the original bug. I can't reproduce it. One more strange issue: dec2hex(2159017984) gives 80B00000 but hex2dec(80B00000) gives -2147483648.
Created attachment 138789 [details] sample file A file converting 2^39-1 and -2^39 from dex to hex and back again. Works in calc, not in gnumeric.
Why is this a blocker? Are you losing all your data as a consequence of this bug (which I doubt is a bug in the any case).
In any case, according to the description of this function: ------------------------------------------------------------ DEC2HEX: hexadecimal representation of the decimal number x Arguments: x: integer places: number of digits ------------------------------------------------------------ Note that x is not restricted to positive integers. Specifically =dec2hex(-1,) results in FFFFFFFFFF which is the correct hexadecimal 2's complement representation of the integer -1. So you are right, as advertised GNuemric works on integers. Where are you reading that it should work on positive integers only? From the OpenFormula draft definition of DEC2HEX: The resulting value is a hexadecimal value, up to 10 digits, with the topmost bit (40th bit) being the sign bit and in two's complement form. office.microsoft.com/en-us/excel/HP052090541033.aspx: If number is negative, places is ignored and DEC2HEX returns a 10-character (40-bit) hexadecimal number in which the most significant bit is the sign bit. The remaining 39 bits are magnitude bits. Negative numbers are represented using two's-complement notation.
All our conversions are bad if the numbers are large enough. See my comments above and the attached sample (open in in calc as well).
Jean: sorry I was only looking at the initial report.
This is strange. WHat the code is doing seems to be correct: 1) we use strtol to translate the original number (which we printed into a buffer) to a number using the appropriate source base, in the case of dec2hex the source base is 10. 2) then we translate that number into the appropriate representation. The problem occurs in 1): 152 v = strtol (buf, &err, src_base); (gdb) p buf $10 = "549755813887\000\000\000\000\000\000\000\220Ò\227\b(i>·\000\000\000@x\203£¿\001\000\000\000P\224½\b\020\000\000\000\000\000\000\000\000\200C@`\203£¿»\\ÿ·" After executing that line of code we have (gdb) p v $14 = 2147483647 which is of course wrong.
Not really wrong. On 32 bit architecture that is indeed the largest value strtol can return and since we never bother to check errno (nor set it to zero before) we don't notice that overflow.
So we should not use strtol since we claim that dec2hex can handle any integer between -549755813888 and 549755813887. And we need that to be compatible with excel and calc.
Replacing strtol with strtoll fixes that issue (but of course we should still check errno for ERANGE) but then b10 = gnm_pow (src_base, 10); if (v >= b10 / 2) /* N's complement */ v = v - b10; is just nonsense. I guess we'll keep this for Morten.
I was just writing the same thing, you were just more quick ;-)
I am an assembler programmer and resolution does not seem so complicated, just shift four bits, create a mask and add '0' or 'A'. I very often use GNumeric and I am waiting for the resolution of this problem. Good luck.
I'll get to this in a week.
This problem has been fixed in the development version. The fix will be available in the next major software release. Thank you for your bug report.