3

This code:

double x = 2.0;
for(int i = 1 ; i<1024 ; i+=i) {
    Console.WriteLine( String.Format( "2^{0} = {1:F0}", i, x ) );
    x*=x;
}

Outputs:

2^1 = 2
2^2 = 4
2^4 = 16
2^8 = 256
2^16 = 65536
2^32 = 4294967296
2^64 = 18446744073709600000
2^128 = 340282366920938000000000000000000000000
2^256 = 115792089237316000000000000000000000000000000000000000000000000000000000000000
2^512 = 13407807929942600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

I thought that double's formula is sign * 2 ^ exponent * fraction; To Illustrate my situation; With setting the fraction to 0.5, the sign to positive, and by setting exponent to any value between -1024 to 1023, I can present any 2^n number that is in the exponent's range; What is wrong with this deduction? Is the formula incomplete?

LyingOnTheSky
  • 2,844
  • 1
  • 14
  • 33

4 Answers4

3

A double can represent powers of 2 exactly, as demonstrated by the following code (which uses Jon Skeet's DoubleConverter class):

Console.WriteLine(String.Format("2^{0} = {1}", i, DoubleConverter.ToExactString(x)));

For the F0 specifier, why did the .NET designers choose to round the value off after the 15 most significant decimal digits?

My guess: Displaying the exact value (such as 18446744073709551616) might imply that the double is precise to all those digits, when in fact a double cannot distinguish between that value and 18446744073709600000. Also, displaying a rounded value is consistent with exponential notation: 1.84467440737096E+19.

Michael Liu
  • 52,147
  • 13
  • 117
  • 150
  • I think this is formatting problem, I just tested it in C++ with `printf` (`printf("%.0lf",...);` and it works. – LyingOnTheSky Nov 19 '14 at 18:12
  • 1
    It is hard to believe that the inexact digits are just set to zero. Why would that be the case if it is instead possible to format the value exactly? – usr Nov 19 '14 at 18:12
  • 1
    This appears to be a correct answer to a different question. – Ben Voigt Nov 19 '14 at 18:13
  • @BenVoigt Why is this? The problem lies in the formatting implemention and not in the double's definition. I won't accept and wait. – LyingOnTheSky Nov 19 '14 at 18:15
  • Is there evidence that this answer is correct? At the moment it is just a guess. – usr Nov 19 '14 at 18:16
  • @usr I tested it in C++ and it works. I just don't know how to fix it in C#. – LyingOnTheSky Nov 19 '14 at 18:18
  • @usr: It's possible to write a conversion routine that displays the *exact* value of a double. However, the exact value would typically be meaningless because it would imply precision that a double doesn't have. Therefore, .NET just rounds the value off when formatting it. – Michael Liu Nov 19 '14 at 18:18
  • That sounds like a choice with purely bad effects. This formatting lessens precision and introduces a bias. Surprising, if true. It is still not proven. The C++ test does not prove it because C++ might just be calculating "more correctly" than C# does it. Indistinguishable at the moment. – usr Nov 19 '14 at 18:20
  • @LyingOnTheSky: Because your question asks about `double`, not about `String.Format`. Michael has answered the question you failed to ask, namely "Why does string.Format return incorrect least significant digits when presented with inputs that are exactly represented?" – Ben Voigt Nov 19 '14 at 18:36
  • @BenVoigt My question is obsolete, because my initial assumption was that `double` is the problem, and not that `String.Format` is the one that made `double` look bad. I am agreeing with your point, but if I will act on it then I will just open new question and close this one. – LyingOnTheSky Nov 19 '14 at 18:44
0

No. Your argument fails at "by setting exponent to any value".

There's a limited range on exponent, you cannot represent

pow(2, 1000000)

even though 1000000 is a natural number.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • 1
    But why it can't handle `2^512`? This is the question. Is it unclear? – LyingOnTheSky Nov 19 '14 at 18:09
  • 1
    Actually 512 is in the range, there's 2048 possibilities to the `exponent` value. That is from -1024 to 1023. – LyingOnTheSky Nov 19 '14 at 18:10
  • 1
    Shouldn't 2^64 be representable? The exponents surely can take the value 64. – usr Nov 19 '14 at 18:11
  • ok, sorry, 1023 is the edge, not 511. There are slightly fewer than 2048 allowed values because of non-finite numbers and denormals (-1024 isn't allowed either) – Ben Voigt Nov 19 '14 at 18:11
  • @usr: `2^64` is `62`. `pow(2, 64)` is representable, what makes you think it's not. – Ben Voigt Nov 19 '14 at 18:14
  • @BenVoigt If it can't represent number because it's out of it's `exponent`'s range, it will just print `Infinity`, just try it. (Change `<1024` to `<=1024` for example) – LyingOnTheSky Nov 19 '14 at 18:16
  • Well, the examples in the question suggest that it is not representable. Or, it is a formatting issue. – usr Nov 19 '14 at 18:21
0

http://msdn.microsoft.com/en-us/library/678hzkk9.aspx

The double keyword signifies a simple type that stores 64-bit floating-point values. The following table shows the precision and approximate range for the double type.

Type
double

Approximate range
±5.0 × 10−324 to ±1.7 × 10308

Precision
15-16 digits
John
  • 6,503
  • 3
  • 37
  • 58
0

That answer to your question is that an IEEE 754 double precision number is a 64-bit value:

  • 1 bit is the sign
  • 11 bits represent the exponent
  • 52 bits represent the significand (but due to a little deep magick, the signficand actually has 53 bits of precision).

It can represent no more than 264 discrete values — the same as a 64-bit integer (and actually less due to things like NaN, positive and negative zero, etc.)

Its range, however, is much larger than that of a 64-bit integer: it can represent decimal values roughly from 10-308 to 10+308 ... albeit with with no more than 15 to 17 decimal digits of precision.

Floating point trades precision for range. It's a tradeoff.

See IEEE-754 Double Precision Binary Floating Point Format for rather more details.

Even better, read David Goldberg's 1991 paper, "What every computer scientist should know about floating-point arithmetic":

Abstract. Floating-point arithmetic is considered as esoteric subject by many people. This is rather surprising, because floating-point is ubiquitous in computer systems: Almost every language has a floating-point datatype; computers from PCs to supercomputers have floating-point accelerators; most compilers will be called upon to compile floating-point algorithms from time to time; and virtually every operating system must respond to floating-point exceptions such as overflow. This paper presents a tutorial on the aspects of floating-point that have a direct impact on designers of computer systems. It begins with background on floating-point representation and rounding error, continues with a discussion of the IEEE floating point standard, and concludes with examples of how computer system builders can better support floating point.

David Goldberg. 1991. "What every computer scientist should know about floating-point arithmetic". ACM Comput. Surv. 23, 1 (March 1991), 5-48. DOI=10.1145/103162.103163 http://doi.acm.org/10.1145/103162.103163

Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135