Python 3.4.0b3+ (default:aab7258a31d3, Feb 7 2014, 10:48:46) [GCC 4.7.3] on linux Type "help", "copyright", "credits" or "license" for more information. --> from decimal import Decimal as D --> 9017.0109812864350067128347806 9017.010981286436 --> D(9017.0109812864350067128347806) Decimal('9017.01098128643570817075669765472412109375')
In case my question isn't obvious, the direct float got me 16 digits, while the Decimal float got me 42 digits. Why is the Decimal more "accurate" that the float it came from?
That's an interesting question. It does appear to be a lot more digits than needed. Here's that float exactly, in hex:
py> 9017.010981286436.hex() '0x1.19c8167d5b50ep+13'
Let's convert it to decimal:
py> digits = list('19c8167d5b50e') py> for i, c in enumerate(digits): ... digits[i] = '0123456789abcdef'.index(c) ... py> d = Decimal(0) py> for n in digits[::-1]: ... d += n ... d /= 16 ... py> d += 1 py> d *= 2**13 py> d Decimal('9017.010981286435708170756694')
,,, So I must admit, I'm not sure where the extra digits come from:
but perhaps my calculation was rather naive.
The calculation is fine, but recall that decimal calculations are limited to 28 significant digits by default. It's no coincidence that len('9017.010981286435708170756694') == 29 (28 digits + a decimal point). The answer has "suffered" multiple rounding errors to make it fit in 28 digits.
Boost the context precision before you start, and you'll get more digits. Keep boosting it, and you'll eventually get 9017.01098128643570817075669765472412109375 followed by (zero or more) trailing zeroes.
A more direct way is to view this as an integer problem: mathematically,
0x1.19c8167d5b50ep+13 is 0x119c8167d5b50e / 2(4*13 - 13) = 0x119c8167d5b50e / 239 = (multiplying top and bottom by 539) 0x119c8167d5b50e * 539 / 10**39
and now it's in the form of an integer numerator divided by a power of
0x119c8167d5b50e * 5**39 9017010981286435708170756697654724121093750