float/double Math.Round in C# [duplicate] - c#

This question already has answers here:
Is floating point math broken?
(31 answers)
Rounding of float values
(2 answers)
Difference between decimal, float and double in .NET?
(18 answers)
Closed 4 years ago.
float ff = (float)31.15;
double dd = 31.15;
var frst = Math.Round(ff, 1, MidpointRounding.AwayFromZero);
var drst = Math.Round(dd, 1, MidpointRounding.AwayFromZero);
frst: 31.1
drst: 31.2
Can someone explain why?

Well, Math.Round wants double, not float, that's why
Math.Round(ff, 1, MidpointRounding.AwayFromZero);
equals to
Math.Round((double)ff, 1, MidpointRounding.AwayFromZero);
and if we inspect (double)ff value
Console.Write(((double)ff).ToString("R"));
we'll see round up errors in action
31.149999618530273
Finally, Math.Round(31.149999618530273, 1, MidpointRounding.AwayFromZero) == 31.1 as expected

In floating point, all numbers are represented internally as fractions where the denominator is a power of 2.
(This is a similar way to how decimals are actually fractions with power-of-10 denominators. So 31.15 is just a way of writing the fraction 3115/100)
In floating point, 31.15 must be represented internally as a binary number. The closest binary fraction is: 1111.1001001100110011001100110011001100110011001100110011001100...repeating
The 1100 recurs (repeats forever), and so the number will be truncated depending on whether it is stored in a double or a float. In a float it is truncated to 24 digits, and in a double to 53.
Exact: 1111.100100110011001100110011001100110011001100110011001100110011001100...forever
Float: 1111.10010011001100110011
Double: 1111.1001001100110011001100110011001100110011001100110
Therefore you can see that the double that this number converts to, is actually slightly larger than the float it converts to. So it is clear that it won't necessarily round to the same number, since it is not the same number to begin with.

Related

Why is (1/90) = 0? [duplicate]

This question already has answers here:
C# is rounding down divisions by itself
(10 answers)
Closed 8 years ago.
I am working in Unity3D with C# and I get a weird result. Can anyone tell me why my code equals 0?
float A = 1 / 90;
The literals 1 and 90 are interpreted as an int. So integer division is used. After that the result is converted to a float.
In general C# will read all sequences (without decimal dot) of digits as an int. An int will be converted to a float if necessary. But before the assignment, that's not necessary. So all calculations in between are done as ints.
In other words, what you've written is:
float A = (float) ((int) 1)/((int) 90)
(made it explicit here, this is more or less what the compiler reads).
Now a division of two int's is processed such that it takes only the integral part into account. The integral part of 0.011111 is 0 thus zero.
If you however modify one of the literals to a floating point (1f, 1.0f, 90f,...) or both, this will work. Thus use one of these:
float A = 1/90.0f;
float A = 1.0f/90;
float A = 1.0f/90.0f;
In that case, floating point division will be performed. Which takes into account both parts.
etc.

Rounding bug in c#? [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 8 years ago.
I'm having problems with a Rounding issue in c#. I would like to round the result of a calculation up to 4 decimals (awayfromzero). If I use Math.Round(variable,...) it rounds down, if I enter the result manually, it rounds up.. I have no idea why..
What am I doing wrong? The result of the below code is:
Rounded: 591.24575 591.2457 - 591.2458
double number1 = 1136.81;
double number2 = 4.00;
double number3 = 2182.257;
double result = (number1 * number2 - number3) / 4;
Console.WriteLine("Rounded: " +result+" " + Math.Round(result, 4, MidpointRounding.AwayFromZero) + " - " + Math.Round(591.24575, 4, MidpointRounding.AwayFromZero));
Console.ReadLine();
If you use my DoubleConverter, you can see the exact value of result:
Console.WriteLine(DoubleConverter.ToExactString(result));
That prints:
591.2457499999999299689079634845256805419921875
... which rounds to 591.2457 when rounded to 4 decimal places. When you just print result, it's printing it already rounded to a certain number of decimal places, which can affect the result if you then (mentally) rounded to 4 DP.
You can see this without any of the "normal" oddities of binary floating point. Consider this code:
decimal exact = 1.2345m;
decimal rounded2 = Math.Round(exact, 2, MidpointRounding.AwayFromZero);
decimal rounded3 = Math.Round(exact, 3, MidpointRounding.AwayFromZero);
decimal rounded3Then2 = Math.Round(rounded3, 2, MidpointRounding.AwayFromZero);
Console.WriteLine(rounded2); // 1.23
Console.WriteLine(rounded3); // 1.235
Console.WriteLine(rounded3Then2); // 1.24
In your code you weren't actually performing the "two roundings" - but you were mentally doing so by taking the printed value of result (591.24575) and assuming you could take that to be accurate in order to round it further.
result is not exactly 591.24575, it is some number that is very close to 591.24575 but it is just slightly smaller, something along the lines of 591.24574999999999, as a result of the fact that certain numbers that have a finite number of digits in base 10 cannot be represented with a finite number of digits in base 2. When you set the number exactly you are avoiding ever having a double set to one of those values as an intermediate value of your calculations.
If you are dealing with numbers that have a known fixed number of base 10 digits and it's important that you not have these precision errors than it may be appropriate to use Decimal in this context.
result doesn't have the value you think it does, it's being truncated by putting it in a string representation. As for why that is, read What Every Computer Scientist Should Read About Floating Point
Take a look while debugging:
result: 591.24574999999993
result.ToString(): "591,24575"

c# double - why is the answer always 0? [duplicate]

This question already has answers here:
Why returns C# Convert.ToDouble(5/100) 0.0 and not 0.05
(7 answers)
Closed 8 years ago.
I have a double that when assigned is always coming back as 0.0, but should not happen.
The code I have is
double test = (27096140 / 27216140);
The answer to this should be 0.9955....
I am not using the double primitive type correctly?
Cheers
Edit
Of course, I was using int and no floating points.
Knew it would be a matter of common sense.
You are using integer division, you should use floating-point division:
double test = (27096140.0 / 27216140);
You are actually performing integer division here because the 2 numbers are whole. That forces the result of the calculation to be int which truncates the precision so you end up with 0.
You need to tell the compiler you are actually working with floating-point numbers and not int's, just adding a floating point to one of the numbers should fix this e.g.
double test = (27096140.0 / 27216140);
Alternatively, you could actually declare the numbers as doubles
double a = 27096140;
double b = 27216140;
double test = (a / b);
Or even cast the number in the calculation
double test = ((double)27096140 / 27216140)
Beacuse you're using integers instead of doubles. Use:
double test = (27096140.0d / 27216140.0d);
The numbers 27096140 and 27216140 are ints, so the result of the division is also an int: 0.
Then this is cast to a double: 0.0

why (1.0E+28f).ToString() == "9.999999E+27"? [duplicate]

This question already has answers here:
Why is floating point arithmetic in C# imprecise?
(3 answers)
Closed 9 years ago.
I am creating a float point control where you can increment by 10, 100, 1000 etc.
The text I display in the control is myFloatNumber.ToString("E");
as I was increasing a number I noticed:
1.0E+1f = 1.0E+1f
1.0E+2f = 1.0E+2f
1.0E+3f = 1.0E+3f
......
......
1.0E+25f = 1.0E+25f
1.0E+26f = 1.0E+26f
1.0E+27f = 1.0E+27f
1.0E+28f = 9.999999E+27f // Why!!?????
The solution to this problem is to use a double but I am very curios as to why is this behavior?
here is the code:
string str1 = (1.0E27f).ToString(); // str1 = "1E+27"
string str2 = (1.0E28f).ToString(); // str2 = "9.999999E+27";
string str3 = (1.0E29f).ToString(); // str3 = "1E+29"
You have to take into account that 1.0e28f is a decimal (base 10) representation.
Converting this string (either a literal in source code or value in a data file) to a floating point imply a conversion to base 2 (the float internal representation).
The 3 nearest floating point values in the neighbourhood of 10^28 are exactly
0.9999998261528069050908803072e28f
0.9999999442119689768320106496e28f <- the nearest one
1.0000000622711310485731409920e28f
or in base 2:
1.00000010011111100111000 * 2^93
1.00000010011111100111001 * 2^93
1.00000010011111100111010 * 2^93
The nearest one (in the middle) is chosen and that is the float in memory, not 1.0e28.
When you request ToString(), you are converting back 0.9999999442119689768320106496e28f to a decimal form.
It sounds like default format is to print 1 decimal before the floating point separator, and 6 decimals after the floating point (much like C printf %f format)
The nearest such decimal to 0.9999999442119689768320106496e28f is indeed 9.999999e27, that's pretty straight forward.
EDIT
Note that 5^3 is near 2^7, since single precision float has 24 bits significand, and 24*3/7 is approximately 10, the maximum power of 5 represented exactly in single precision float is 5^10.
Hence, the maximum power of 10 representable exactly in float is 1.0e10.
Every power from 11 to 27 did print like you expect somehow by luck.
Well, not exactly by luck, but because the roundoff error was less than 0.5*10^(n-7).
EDIT 2 - about double
And double does not really "solve" things, because with 53 bits significand you can go up to 53*3/7 that is 10^22 without rounding error.
Every power of 10 from 23 and above are subject to round off.
It somehow solves however if you keep printing 6 decimals, because the round off occurs around the 15th digit.

Floating point conversions c# [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
.Net float to double conversion
I though I understood floating point but can someone explain the following
float f = 1.85847987E+9F;
double d = Convert.ToDouble(f);
d is now converted to a string as 1858479872.0. I'm assuming the extra 2 is because double cannot represent the floating point number exactly.
My question is why does it seem to be able to rerepsent the same number when assigned directly
double d = 1.85847987E+9;
and it is shown exactly as 185847987.0
Because double can, and float cannot represent 1.85847987E+9 precisely.
Why the compiler doesn't complains about "float f = 1.85847987E+9F;" if it cant represents it properly
As per C# specification, section 4.1.6 Floating point types
The floating-point operators, including the assignment operators, never produce exceptions.
The problem is not double but float. Float is limited to 32 bit, while double uses 64 bit for precision.
Because a float exists out of a sign, mantissa and exponent. See Jon Skeet's answer here how to extract those values.
For 1.85847987E+9F, the mantissa is 7259687 and the exponent is 8. Then mantissa << exponent equals 1858479872. Since the precision for a float is limited to 7 digits, the value of any digit beyond 7 digits depends on the implementation, not the input. You can test this easily by inputting 123456789F.

Categories

Resources