BrowserUK did a good job of explaining the real issue, which you now get, but I wanted to further clarify a tangential point:
*... for literal floating point values you would in general have to write them in a number base of a power of two if you want to express ... them exactly.*
It's one of the mathematical niceties of binary that *any* binary floating point can be exactly represented in decimal. It comes about because 2 (binary) is a factor of 10 (decimal: 2*5)
` x = c * (2**p) # the value you want to express
c # the coefficient
p = -n # the smallest power of two that goes into x;
# negative, since it's a binary fraction
x = c*(2**p) = c*(2**-n) = ...
[ 1 ] [ 1 ] [ 5**n ] [ 5**n ]
= ... = c*[------] = c*[------]*[------] = c*[-------] = ...
[ 2**n ] [ 2**n ] [ 5**n ] [ 10**n ]
= ... = c * (5**n) * (10**-n) = c * (5**n) ** (10**p)
k = c * (5**n) # k integer, so exactly representable in decimal
x = k * (10**-n) # since n is finite and k is an integer,
# x is exactly representable in decimal
`
As might be obvious from the final statement, an n-digit binary fixed point can be expressed exactly in an n-digit decimal fixed point.
It turns out, there's something else interesting you can tell about the number of digits for an exact power of two: specifically, which digit d (after the decimal point) that the decimal expansion will start on
`x c*(2**-n) binary decimal d log10(x)
1/2 1*(2**-1) 0b0.1 0.5 1 -0.301029996
1/4 1*(2**-2) 0b0.01 0.25 1 -0.602059991
3/4 3*(2**-2) 0b0.11 0.75 1 -0.124938737
1/8 1*(2**-3) 0b0.001 0.125 1 -0.903089987
7/8 7*(2**-3) 0b0.111 0.875 1 -0.057991947
1/16 1*(2**-4) 0b0.0001 0.0625 2 -1.204119983
15/16 15*(2**-4) 0b0.1111 0.9375 1 -0.028028724
1/32 1*(2**-5) 0b0.00001 0.03125 2 -1.505149978
1/64 1*(2**-6) 0b0.000001 0.015625 2 -1.806179974
1/128 1*(2**-7) 0b0.0000001 0.0078125 3 -2.107209970
3/128 3*(2**-7) 0b0.0000011 0.0234375 2 -1.630088715
5/128 5*(2**-7) 0b0.0000101 0.0390625 2 -1.408239965
9/128 9*(2**-7) 0b0.0001001 0.0703125 2 -1.152967460
13/128 13*(2**-7) 0b0.0001101 0.1015625 1 -0.993266617
`
You might see that d = -floor(log10(x)) = ceil(-log10(x)). In general, for a given x = c*(2**-n) < 1, the decimal expression will start on the d^{th} digit after the decimal point, and end on the n^{th} digit after the decimal point; thus, the length of the decimal expansion (ignoring leading and trailing zeroes) is `L = n - d + 1`.
For example, the smallest representable 52bit fraction `x = 2**-52 = 2.2204...e-16`: it will start on the 16th digit (`log10(x)=-15.654 -> d=16`) and run to the 52nd digit. Double precision floating-point numbers (the common native floating-point in perl5) use a 52bit fractional component, with the encoding usually meaning one plus the fractional part times some power of two (`x = (1+f)*(2**p)`). So, that `(1+f)` can be exactly expressed in decimal as
`1.0000 0000 0000 000f ffff ffff ffff ffff ffff ffff ffff ffff ffff
^1 16^ 52^
+
^ points to the nth digit after decimal point
`
And thus, you need the 16 digits after the decimal point to indicate the last bit of accuracy in the underlying binary fraction, as BrowserUK said. (But you would need all 52 decimal digits after the decimal point to exactly represent the full value.)
Sorry, I like stuff like this: all this to say: you can exactly represent any n-digit binary fraction within n decimal digits after the decimal point. |
Comment onRe^2: Variables are automatically rounded off in perl (humans)DownloadCode