Example of seemingly equal float variables not equal [duplicate] - c#

This question already has answers here:
Floating point inaccuracy examples
(7 answers)
Closed 3 years ago.
Can anyone show me an example of two C# variables containing float values that "seem" to be equal but in fact are not. When I say "seem equal", what I mean is that they intuitively seem to be equal.
The reason why I'm looking for such an example is because I have code that compares two float variables for equality and Visual Studio is warning me that Comparison of floating point numbers can be unequal due to the differing precision of the two values.. I understand that float variables are not precise (here's a StackOverflow question where this is discussed and explained very clearly) but I am failing to find an actual example where two values that seem to be equal are actually considered different by C#.
For instance, the first answer to the SO question I referenced earlier mentions that 9.2 and 92/10 are internally represented differently so I wrote the following code to verify if C# would treat them as equal or not and the result is that they are considered equal.
var f1 = 92f / 10f;
var f2 = 9.2f;
if (f1 == f2)
{
Console.Write("Equal, as expected");
}
else
{
Console.Write("Surprisingly not equal");
}
So, I'm looking for an example of f1 and f2 that "seem" to be equal but would cause C# to treat them as different.

If you don't insist on float (Single) type, but actually want any floating point types (Single, Double) example you can try:
if (Math.Sqrt(2.0) * Math.Sqrt(2.0) == 2.0)
Console.Write("Equal, as expected");
else
Console.Write("Surprisingly not equal");

Try the code below. value1 and value2 both represent toSum * 10, but they are not equal. At least on my working machine. Float type has especially low precision on large values.
const float toSum = 1000000000.1f;
const int count = 10;
float value1 = 0;
for (int i = 0; i < count; i++)
{
value1 += toSum;
}
float value2 = toSum * count;
var equal = value1 == value2;

Related

Comparing the sum of floats [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 2 years ago.
I am running this code in Unity (Mono backend with .Net 4.x)
float a = 0.42434249394294f;
float b = 1 - a;
float sum = a + b;
bool compare1 = (a + b) >= 1f;
bool compare2 = sum >= 1f;
In Debugging (with Visual Studio), compare1 is false while compare2 is true.
How is this happening? Why are the last two lines different? I would think that sum == a + b.
You have encountered a very common numerical precision error called a round-off error. When summing floating point values, you need to include an error tolerance. This kind of error is inherent to floating point math operations in all programming languages.
Your code should be changed to something like the below:
const float errorTolerance = 0.000001f;
float target1 = a + b;
float target2 = sum;
bool compare1 = Math.Abs(target1 - 1f) <= errorTolerance;
bool compare2 = Math.Abs(target2 - 1f) <= errorTolerance;
Note also with a float in c#, it is a single precision floating point number and has only 6-7 significant digits of accuracy.
From this answer:
2.) Floating point intermediate results often use 80 bit precision in register, but only 64 bit in memory.
I believe, that sum = a + b generates an instruction to store the result in memory, as a float with a maximum of 64 bits.
Due to a compiler optimization, the machine code of (a + b) >= 1f doesn't seem to cast to the limited float type and apparently uses a higher bit depth, where it can be observed that the numbers don't add up to 1.
We can force memory storage by casting (float)(a+b).
From Enigmativity's comment:
[...] the output is different if you have compiler optimisation turned on or not. When it's on I get true and true. When it is off I get false and true.

Conversion String to Float fail for some number but not others

I have the following numbers as strings; 22570438, 22570481, 22570480.
var listOfStrings = new List<string> { "22570438", "22570481", "22570480" };
foreach (var val in listOfStrings)
{
float numTest = 0;
numTest = Convert.ToInt64(float.Parse(val));
numTest = long.Parse(val);
numTest = float.Parse(val.ToString().TrimStart().TrimEnd(), CultureInfo.InvariantCulture.NumberFormat);
}
For number, 22570438, in these 3 instances the number returned is 22570438, as with 22570480
But for 22570481, these 3 instances return 22570480. Code below is a sample how I'm doing the testing and not an code issue. I have tried it in other projects and still getting same result.
Has anyone experience this issue and is it a compiler issue when converting 22570481 to a float ??
I tried finding similar questions but If anyone knows a post that could help please reply with link.
float has limited precision; it can't accurately store arbitrary integers beyond a certain size, and it doesn't have the precision to retain what you want here.
Consider using int, decimal or double instead.
It is not a compiler bug or a runtime bug. It is a fundamental feature of floating point arithmetic (in this case 32-bit IEEE 754 floating points)

How to use Newton-Raphson method to find the square root of a BigInteger in C#

So I'm attempting to use the Newton-Raphson method to find the square root of a BigInteger.
Here is my code:
private void sqrRt(BigInteger candidate)
{
BigInteger epsilon = new BigInteger(0.0001);
BigInteger guess = candidate / 2;
while (BigInteger.Abs(guess * guess - candidate) >= epsilon)
{
// guess = guess - (((guess**2) - y)/(2*guess))
guess = BigInteger.Subtract(guess, BigInteger.Divide(BigInteger.Subtract(BigInteger.Multiply(guess, guess), candidate), BigInteger.Multiply(2, guess)));
MessageBox.Show(Convert.ToString(guess));
}
}
The problem seems to be that the BigInteger is not precise enough to fall within the degree of accuracy of the epsilon in the while loop - i.e. it needs a decimal place. My question is what/how/where do I convert to a double to make the while loop eventually return false?
You are using the wrong data type. In order to have decimal points, you would need to use double, float, decimal, or Complex.
Check the links of all these types so you can see their digits of precision.

Division in C# to get exact value [duplicate]

This question already has answers here:
Why does integer division in C# return an integer and not a float?
(8 answers)
Closed 9 years ago.
If I divide 150 by 100, I should get 1.5. But I am getting 1.0 when I divided like I did below:
double result = 150 / 100;
Can anyone tell me how to get 1.5?
try:
double result = (double)150/100;
When you are performing the division as before:
double result = 150/100;
The devision is first done as an Int and then it gets cast as a double hence you get 1.0, you need to have a double in the equation for it to divide as a double.
Cast one of the ints to a floating point type. You should look into the difference between decimal and double and decide which you want, but to use double:
double result = (double)150 / 100;
Make the number float
var result = 150/100f
or you can make any of number to float by adding .0:
double result=150.0/100
or
double result=150/100.0
double result = (150.0/100.0)
One or both numbers should be a float/double on the right hand side of =
If you're just using literal values like 150 and 100, C# is going to treat them as integers, and integer math always "rounds down". You can add a flag like "f" for float or "m" for decimal to not get integer math. So for example result = 150m/100m will give you a different answer than result = 150/100.

Comparing double values in C#

I've a double variable called x.
In the code, x gets assigned a value of 0.1 and I check it in an 'if' statement comparing x and 0.1
if (x==0.1)
{
----
}
Unfortunately it does not enter the if statement
Should I use Double or double?
What's the reason behind this? Can you suggest a solution for this?
It's a standard problem due to how the computer stores floating point values. Search here for "floating point problem" and you'll find tons of information.
In short – a float/double can't store 0.1 precisely. It will always be a little off.
You can try using the decimal type which stores numbers in decimal notation. Thus 0.1 will be representable precisely.
You wanted to know the reason:
Float/double are stored as binary fractions, not decimal fractions. To illustrate:
12.34 in decimal notation (what we use) means
1 * 101 + 2 * 100 + 3 * 10-1 + 4 * 10-2
The computer stores floating point numbers in the same way, except it uses base 2: 10.01 means
1 * 21 + 0 * 20 + 0 * 2-1 + 1 * 2-2
Now, you probably know that there are some numbers that cannot be represented fully with our decimal notation. For example, 1/3 in decimal notation is 0.3333333…. The same thing happens in binary notation, except that the numbers that cannot be represented precisely are different. Among them is the number 1/10. In binary notation that is 0.000110011001100….
Since the binary notation cannot store it precisely, it is stored in a rounded-off way. Hence your problem.
double and Double are the same (double is an alias for Double) and can be used interchangeably.
The problem with comparing a double with another value is that doubles are approximate values, not exact values. So when you set x to 0.1 it may in reality be stored as 0.100000001 or something like that.
Instead of checking for equality, you should check that the difference is less than a defined minimum difference (tolerance). Something like:
if (Math.Abs(x - 0.1) < 0.0000001)
{
...
}
You need a combination of Math.Abs on X-Y and a value to compare with.
You can use following Extension method approach
public static class DoubleExtensions
{
const double _3 = 0.001;
const double _4 = 0.0001;
const double _5 = 0.00001;
const double _6 = 0.000001;
const double _7 = 0.0000001;
public static bool Equals3DigitPrecision(this double left, double right)
{
return Math.Abs(left - right) < _3;
}
public static bool Equals4DigitPrecision(this double left, double right)
{
return Math.Abs(left - right) < _4;
}
...
Since you rarely call methods on double except ToString I believe its pretty safe extension.
Then you can compare x and y like
if(x.Equals4DigitPrecision(y))
Comparing floating point number can't always be done precisely because of rounding. To compare
(x == .1)
the computer really compares
(x - .1) vs 0
Result of sybtraction can not always be represeted precisely because of how floating point number are represented on the machine. Therefore you get some nonzero value and the condition evaluates to false.
To overcome this compare
Math.Abs(x- .1) vs some very small threshold ( like 1E-9)
From the documentation:
Precision in Comparisons
The Equals method should be used with caution, because two apparently equivalent values can be unequal due to the differing precision of the two values. The following example reports that the Double value .3333 and the Double returned by dividing 1 by 3 are unequal.
...
Rather than comparing for equality, one recommended technique involves defining an acceptable margin of difference between two values (such as .01% of one of the values). If the absolute value of the difference between the two values is less than or equal to that margin, the difference is likely to be due to differences in precision and, therefore, the values are likely to be equal. The following example uses this technique to compare .33333 and 1/3, the two Double values that the previous code example found to be unequal.
So if you really need a double, you should use the techique described on the documentation.
If you can, change it to a decimal. It' will be slower, but you won't have this type of problem.
Use decimal. It doesn't have this "problem".
Exact comparison of floating point values is know to not always work due to the rounding and internal representation issue.
Try imprecise comparison:
if (x >= 0.099 && x <= 0.101)
{
}
The other alternative is to use the decimal data type.
double (lowercase) is just an alias for System.Double, so they are identical.
For the reason, see Binary floating point and .NET.
In short: a double is not an exact type and a minute difference between "x" and "0.1" will throw it off.
Double (called float in some languages) is fraut with problems due to rounding issues, it's good only if you need approximate values.
The Decimal data type does what you want.
For reference decimal and Decimal are the same in .NET C#, as are the double and Double types, they both refer to the same type (decimal and double are very different though, as you've seen).
Beware that the Decimal data type has some costs associated with it, so use it with caution if you're looking at loops etc.
Official MS help, especially interested "Precision in Comparisons" part in context of the question.
https://learn.microsoft.com/en-us/dotnet/api/system.double.equals
// Initialize two doubles with apparently identical values
double double1 = .333333;
double double2 = (double) 1/3;
// Define the tolerance for variation in their values
double difference = Math.Abs(double1 * .00001);
// Compare the values
// The output to the console indicates that the two values are equal
if (Math.Abs(double1 - double2) <= difference)
Console.WriteLine("double1 and double2 are equal.");
else
Console.WriteLine("double1 and double2 are unequal.");
1) Should i use Double or double???
Double and double is the same thing. double is just a C# keyword working as alias for the class System.Double
The most common thing is to use the aliases! The same for string (System.String), int(System.Int32)
Also see Built-In Types Table (C# Reference)
Taking a tip from the Java code base, try using .CompareTo and test for the zero comparison. This assumes the .CompareTo function takes in to account floating point equality in an accurate manner. For instance,
System.Math.PI.CompareTo(System.Math.PI) == 0
This predicate should return true.
// number of digits to be compared
public int n = 12
// n+1 because b/a tends to 1 with n leading digits
public double MyEpsilon { get; } = Math.Pow(10, -(n+1));
public bool IsEqual(double a, double b)
{
// Avoiding division by zero
if (Math.Abs(a)<= double.Epsilon || Math.Abs(b) <= double.Epsilon)
return Math.Abs(a - b) <= double.Epsilon;
// Comparison
return Math.Abs(1.0 - a / b) <= MyEpsilon;
}
Explanation
The main comparison function done using division a/b which should go toward 1. But why division? it simply puts one number as reference defines the second one. For example
a = 0.00000012345
b = 0.00000012346
a/b = 0.999919002
b/a = 1.000081004
(a/b)-1 = 8.099789405475458e-5‬
1-(b/a) = 8.100445524503848e-5‬
or
a=12345*10^8
b=12346*10^8
a/b = 0.999919002
b/a = 1.000081004
(a/b)-1 = 8.099789405475458e-5‬
1-(b/a) = 8.100445524503848e-5‬
by division we get rid of trailing or leading zeros (or relatively small numbers) that pollute our judgement of number precision. In the example, the comparison is of order 10^-5, and we have 4 number accuracy, because of that in the beginning code I wrote comparison with 10^(n+1) where n is number accuracy.
Adding onto Valentin Kuzub's answer above:
we could use a single method that supports providing nth precision number:
public static bool EqualsNthDigitPrecision(this double value, double compareTo, int precisionPoint) =>
Math.Abs(value - compareTo) < Math.Pow(10, -Math.Abs(precisionPoint));
Note: This method is built for simplicity without added bulk and not with performance in mind.
As a general rule:
Double representation is good enough in most cases but can miserably fail in some situations. Use decimal values if you need complete precision (as in financial applications).
Most problems with doubles doesn't come from direct comparison, it use to be a result of the accumulation of several math operations which exponentially disturb the value due to rounding and fractional errors (especially with multiplications and divisions).
Check your logic, if the code is:
x = 0.1
if (x == 0.1)
it should not fail, it's to simple to fail, if X value is calculated by more complex means or operations it's quite possible the ToString method used by the debugger is using an smart rounding, maybe you can do the same (if that's too risky go back to using decimal):
if (x.ToString() == "0.1")
Floating point number representations are notoriously inaccurate because of the way floats are stored internally. E.g. x may actually be 0.0999999999 or 0.100000001 and your condition will fail. If you want to determine if floats are equal you need to specify whether they're equal to within a certain tolerance.
I.e.:
if(Math.Abs(x - 0.1) < tol) {
// Do something
}
My extensions method for double comparison:
public static bool IsEqual(this double value1, double value2, int precision = 2)
{
var dif = Math.Abs(Math.Round(value1, precision) - Math.Round(value2, precision));
while (precision > 0)
{
dif *= 10;
precision--;
}
return dif < 1;
}
To compare floating point, double or float types, use the specific method of CSharp:
if (double1.CompareTo(double2) > 0)
{
// double1 is greater than double2
}
if (double1.CompareTo(double2) < 0)
{
// double1 is less than double2
}
if (double1.CompareTo(double2) == 0)
{
// double1 equals double2
}
https://learn.microsoft.com/en-us/dotnet/api/system.double.compareto?view=netcore-3.1

Categories

Resources