This question already has answers here:
Comparing double values in C#
(18 answers)
Closed 8 years ago.
I have this code:
static void Main()
{
float i;
for (i = 0; i <= 100; i = i + 0.01F)
{
Console.WriteLine(i);
}
}
And it prints me this:
0
0.01
0.02
0.03
0.04
0.05
0.05999999
0.06999999
0.07999999
0.08999999
0.09999999
0.11
Is this a bug or am I doing something wrong?
Is there any solution to this?
It is not a bug. This is a fundamental property of floating point numbers. The numbers are stored as a mantissa and an exponent and they cannot represent every number possible with perfect precision. If you need precision, you have to use decimal types.
For a lot of information about this see What Every Computer Scientist Should Know About Floating-Point Arithmetic
Related
This question already has answers here:
Is floating point math broken?
(31 answers)
Is double Multiplication Broken in .NET? [duplicate]
(6 answers)
Why is floating point arithmetic in C# imprecise?
(3 answers)
Closed 2 years ago.
I'm trying to create a system where numbers like 1,000 get converted over to 1k, 1,000,000 to 1m, etc. The code works great up until I input a number like 8,850,000. Instead of spitting out 8.85B, it spits out 8.849999B. Is this a quirk with Unity and or C#, or did I do something wrong in the code?
Edit: It wasn't the Mathf.Round function, it was the limitations of the float data type. I managed to fix the problem by using the decimal data type instead.
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;
public class MoneyManager : MonoBehaviour
{
public Text txt;
private static float totalMoney;
public float perClick;
private float decimalMoney;
private float roundedMoney;
private string[] numberletter = new string[] { "K", "B", "T" };
private string correctletter;
void Start()
{
CookieClick.clickAmount = perClick;
}
void Update()
{
totalMoney = CookieClick.money;
roundedMoney = Mathf.Floor(Mathf.Log10(totalMoney));
if(roundedMoney >= 3 && roundedMoney < 6)
{
correctletter = numberletter[0];
decimalMoney = Mathf.Round(totalMoney/1000f * 100.0f) * 0.01f;
Debug.Log(decimalMoney);
txt.text = decimalMoney.ToString() + correctletter;
}
else if(roundedMoney >= 6 && roundedMoney < 9)
{
correctletter = numberletter[1];
Debug.Log(totalMoney);
decimalMoney = Mathf.Round(totalMoney/1000000f * 100.0f) * 0.01f;
Debug.Log(decimalMoney);
txt.text = decimalMoney.ToString() + correctletter;
}
else
{
txt.text = totalMoney.ToString();
}
}
}
It's nothing to do with the rounding, it's just that a number like 8.85 can't be exactly represented as a float.
Floating point numbers are stored in "scientific notation" in base 2. If you write 8.85 in base 2 it's
1000.11011001100110011001100..._2 (repeating forever)
so in the computer this will be stored as
1.0001101100110011001100_2 x 2^3
where the "mantissa" on the left has been chopped off at 23 bits.
Because of this truncation of the binary expansion, the number that's actually stored is equal to
8.84999847412109375
in this case, and so when the computer converts it back to decimal to print it out in a human-readable form that's what you see.
This isn't anything special to the programming language; it's just how numbers work when you can only store so many places.
As Johan Donne mentions in the comments, you can instead instruct the computer to store this number as
885 x 10^(-2)
by using the decimal type instead of float; alternately, you could have taken that number 8.84999... above and rounded it to few enough places that it would have rounded up to 8.85.
This is not caused by Math.Round but by the data type you are using: float stores the numbers with binary fractions. So float cannot always represent a decimal value exactly. Sometimes, when you amplificate the error by multplying with a large value and showing the result or when doing many chained calculations, these errors becomes visible.
Specifically to avoid those small errors, there is the datatype decimal which stores values with decimal fractions. Whenever you want exact results using decimal numbers (e.g. in financial calculations) you should use decimal and not float or double.
So, use decimal instead of float (for the literals as well. e.g. replace 100.0fwith 100.0m).
Note: Not only does decimal store decimal values without rounding errors (even after multiple chained calculations), it also has a much higher precision: 28 digits versus 15 digits in the case of double.
On the other hand, the range for decimal is smaller than is the case for double: see https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types for an overview.
This question already has an answer here:
Why does my float of 999999999 become 10000000000? [duplicate]
(1 answer)
Closed 4 years ago.
In C#, to convert int to float, we just need to do something like float floatNumber = intNumber or Convert.ToSingle(intNumber). However, when it comes to large number such as 999999999, the system cannot correctly convert the number but convert it into the unwanted number 1E+09. Now the question is, is it possible to convert that large integer into the wanted float number?
A 32-bit float can't exactly represent an integer that large: It only has 24 bits with which to do it (one is implicit in the format). In 24 bits you can represent 16777215. 16777216 also fits because it is a power of two. 999999999 can't be represented exactly as a number with at most 24 bits multiplied by a power of 2.
See this answer on SO: https://stackoverflow.com/a/3793950/751579
For more information look up details on IEEE floating point 32-bit and 64-bit formats.
Can you use decimal type?
Console.WriteLine(999999999.0f.ToString("N"));
Console.WriteLine(999999999.0m.ToString("N"));;
prints
1,000,000,000.00
999,999,999.00
The reference even has a example for a very large number
In this example, the output is formatted by using the currency format string. Notice that x is rounded because the decimal places exceed $0.99. The variable y, which represents the maximum exact digits, is displayed exactly in the correct format.
public class TestDecimalFormat
{
static void Main()
{
decimal x = 0.999m;
decimal y = 9999999999999999999999999999m;
Console.WriteLine("My amount = {0:C}", x);
Console.WriteLine("Your amount = {0:C}", y);
}
}
/* Output:
My amount = $1.00
Your amount = $9,999,999,999,999,999,999,999,999,999.00
*/
This question already has answers here:
Why is modulus operator not working for double in c#?
(6 answers)
Closed 4 years ago.
Hi I'm having this really weird issue with C#.
I'm trying to do a modulu operation:
double stepSize = 3.6;
if (180.0 % stepSize != 0) DoStuff();
And 180.0 % 3.6 = 0 -> "proof"
But for some reason C# returns: 3.6
Do any one have an explanation for that
The problem is the floating-point arithmetics and its inability to represent all decimal numbers precisely. A simple test reveals the differences:
decimal type:
Console.WriteLine(180m % 3.6m); // 0.0
float type:
Console.WriteLine(180f % 3.6f); // 4.768372E-06
double type:
Console.WriteLine(180d % 3.6d); // 3.6
This question already has answers here:
Division returns zero
(8 answers)
Closed 5 years ago.
Im trying to get 75% of the CTotal but as it is a decimal number it is rounding 0.75 to 0, does anyone know of a work around
decimal refundtot = order.CTotal;
//change it as it is making it = 0
refundtot = (75 / 100) * refundtot;
refund.RefundTotal = refundtot;
You should use one decimal number when you dividing numbers.
Your code should look like this :
efundtot = ((decimal)75 / 100) * refundtot;
This question already has answers here:
How do I round to the nearest 0.5?
(10 answers)
Closed 9 years ago.
I'm trying to round some values as the following examples and need some help to write the math calculation for it:
input -> 25 ÷ 4 = 6.25 output -> 6.5
input -> 15.5 ÷ 4 = 3.875 output -> 4.0
input -> 24.5 ÷ 4 = 6.125 output -> 6.0
any idea how to write the round math procedure please?!
This should do it.
double Divide(double numerator, double denominator)
{
double result = numerator / denominator;
//round to nearest half-integer
result = Math.Round(result * 2, MidpointRounding.AwayFromZero) / 2;
// due to peculiarities of IEEE754 floating point arithmetic
// we need to round again after dividing back by two
// to avoid a result like 1.49999999.
return Math.Round(result, 1);
}
Sorry for not aware the difficulty you encountered, so I guess maybe the different types of floating point number. Following code just does that:
public static decimal RoundedDivide<T>(T a, T b) {
var x=2*Convert.ToDecimal(a)/Convert.ToDecimal(b);
x=((int)(.5m+x)>x?1:0)+(int)x;
return x/2;
}
Two things to note:
I cannot bound a constraint of ValueType, so if you pass objects of reference types, it may throw
If you wish double as the return type, then just change it and also change .5m to .5, Convert.ToDecimal to Convert.ToDouble