Eerik Sweden
Eerik Sweden

Reputation: 415

c# print float values with more precision

I want to print floats with greater precision than is the default.

For example when I print the value of PI from a float i get 6 decimals. But if I copy the same value from the float into a double and print it i get 14 decimals.

Why do I get more precision when printing the same value but as a double?

How can I get Console.WriteLine() to output more decimals when printing floats without needing to copy it into a double first?

I also tried the 0.0000000000 but it did not write with more precision, it just added more zeroes. :-/

My test code:

float x = (float)Math.PI;
double xx = x;
Console.WriteLine(x);
Console.WriteLine(xx);

Console.WriteLine($"{x,18:0.0000000000}"); // Try to force more precision 
Console.WriteLine($"{xx,18:0.0000000000}");

Output:

3,141593
3,14159274101257
      3,1415930000  <-- The program just added more zeroes :-(
      3,1415927410

I also tried to enter PI at https://www.h-schmidt.net/FloatConverter/IEEE754.html

The binary float representation of PI is 0b01000000010010010000111111011011

So the value is: 2 * 0b1.10010010000111111011011 = 2 * 1.57079637050628662109375 = 3.1415927410125732421875

So there are more decimals to output. How would I get C# to output this whole value?

Upvotes: 1

Views: 10084

Answers (3)

manishnitte
manishnitte

Reputation: 211

To print the value with 6 places after the decimal.

Console.WriteLine("{0:N6}", (double)2/3);

Output :

0.666667

Upvotes: 0

Luaan
Luaan

Reputation: 63742

There is no more precision in a float. When you convert it to a double, the accuracy is worse, even though the precision (number of digits) increased - basically, all those extra digits you see in the double print are conversion artifacts - they are wrong, just the best representation of that given float number you can get in a double. This has everything to do with how binary floating point numbers work.

Let's look at the binary representation of the float:

01000000010010010000111111011100

The first bit is sign, the next eight are the exponent, and the rest is the mantissa. What do we get when we cast it to a double? The exponent stays the same, but the mantissa is filled in with zeroes. But that actually changes the number - you get 3.1415929794311523 (rounded, as always with binary floats) instead of the correct 3.14159265358979 double value of pi. You get the illusion of greater precision, but it's only an illusion - the number is no more accurate than before, you just replaced zeroes with noise.

There's no 1:1 mapping between floats and doubles. The same float value can be represented by many different double values, and the decimal representation of the number can change accordingly. Every cast of float to double should be followed by a rounding operation if you care about decimal precision. Consider this code instead:

double.Parse(((float)Math.PI).ToString())

Instead of casting the float to a double, I first changed it to a decimal representation (in a string), and created the double from that. Now instead of having a "truncated" double, you have a proper double that doesn't lie about extra precision; when you print it out, you get 3.1415930000. Still rounded, of course, since it's still a binary->decimal conversion, but no longer pretending to have more precision than is actually there - the rounding happens at a later digit than in the float version, the zeroes are really zeroes, except for the last one (which is only approximately zero).

If you want real decimal precision, you might want to use a decimal type (e.g. int or decimal). float and double are both binary numbers, and only have binary precision. A finite decimal number isn't necessarily finite in binary, just like a finite trinary number isn't necessarily finite in decimal (e.g. 1/3 doesn't have a finite decimal representation).

Upvotes: 6

Adwaenyth
Adwaenyth

Reputation: 2110

A float within c# has a precision of 7 digits and no more. That means 1 digit before the decimal and 6 after.

If you do have any more digits in your output, they might be entirely wrong.

If you do need more digits, you have to use either double which has 15-16 digits precision or decimal which has 28-29 digits.

See MSDN for reference.

You can easily verify that as the digits of PI are a little different from your output. The correct first 40 digits are: 3.14159 26535 89793 23846 26433 83279 50288 4197

Upvotes: 3

Related Questions