Reputation: 862
In order to check if difference between two float numbers is 0.01 I do this
if ((float1 - float.Parse(someFloatAsStringFromXML).ToString(), System.Globalization.CultureInfo.InvariantCulture)).ToString() == "0,01000977")
Is this type of "approach" is acceptable? Is there better way? How to?
p.s. I'm very new to c# and strong typing languages! So, if you have more than brief explanation, I would love to read it!
I forgot to mention, that numbers are "353.58" and "353.59". I have them as strings with dot "." not "," that is the reason why I use float.Parse
Upvotes: 4
Views: 2529
Reputation: 109547
Firtly, you should always compare numbers as their underlying types (float, double, decimal), NOT as strings.
Now, you might think that you can compare like so:
float floatFromXml = float.Parse(someFloatAsStringFromXML);
if (Math.Abs(float1 - floatFromXml) == 0.01)
My example works as follows:
Firstly, calculate the difference between the two values:
float1 - floatFromXml
Then take the absolute value of that (which just removes the minus sign)
Math.Abs(float1 - floatFromXml)
Then see if that value is equal to 0.01:
if (Math.Abs(float1 - floatFromXml) == 0.01)
And if you don't want to ignore the sign, you wouldn't do the Math.Abs()
part:
if ((float1 - floatFromXml) == 0.01)
But that won't work for your example because of rounding errors!
Because you are using floats (and this would apply to doubles too) you are going to get rounding errors which makes comparing the difference to 0.01 impossible. It will be more like 0.01000001 or some other slightly wrong value.
To fix that, you have to compare the actual difference to the target difference, and if that is only different by a tiny amount you say "that'll do".
In the following code, target
is the target difference that you are looking for. In your case, it is 0.01
.
Then epsilon
is the smallest amount by which target
can be wrong. In this example, it is 0.00001
.
What we are saying is "if the difference between the two numbers is within 0.00001 of 0.1, then we will consider it as matching a difference of 0.1".
So the code calculates the actual difference between the two numbers, difference
, then it sees how far away that difference is from 0.01
and if it is within 0.00001
it prints "YAY".
using System;
namespace Demo
{
class Program
{
void Run()
{
float f1 = 353.58f;
float f2 = 353.59f;
if (Math.Abs(f1 - f2) == 0.01f)
Console.WriteLine("[A] YAY");
else
Console.WriteLine("[A] Oh dear"); // This gets printed.
float target = 0.01f;
float difference = Math.Abs(f2 - f1);
float epsilon = 0.00001f; // Any difference smaller than this is ok.
float differenceFromTarget = Math.Abs(difference - target);
if (differenceFromTarget < epsilon)
Console.WriteLine("[B] YAY"); // This gets printed.
else
Console.WriteLine("[B] Oh dear");
}
static void Main()
{
new Program().Run();
}
}
}
However, the following is probably the answer for you
Alternatively, you can use the decimal
type instead of floats, then the direct comparison will work (for this particular case):
decimal d1 = 353.58m;
decimal d2 = 353.59m;
if (Math.Abs(d1 - d2) == 0.01m)
Console.WriteLine("YAY"); // This gets printed.
else
Console.WriteLine("Oh dear");
Upvotes: 5
Reputation: 612804
You give an example of your two numbers
353.58 353.59
These numbers cannot be exactly represented in binary floating point format. Also, the value 0.01
cannot be exactly represented in binary floating point format. Please read What Every Computer Scientist Should Know About Floating-Point Arithmetic.
So, for example, when you try to represent 353.58
as a float
, there is no float
with that value and you get the closest float value which happens to be 353.579986572265625.
In my view you are using the wrong data type to represent these values. You need to be using a decimal format. That will allow you to represent these values exactly. In C# you use the decimal
type.
Then you can write:
decimal value1 = 353.58m;
decimal value2 = 353.59m;
Debug.Assert(Math.Abs(value2-value1) == 0.01m);
Use decimal.Parse()
or decimal.TryParse()
to convert from your textual representation of the number into a decimal
value.
Upvotes: 3
Reputation: 13844
This isn't a good way of doing it. There's no need to compare it to a string and you don't gain anything by doing it that way. Compare it to an actual float value.
The immediately visible problem with your approach there is it's not culture safe. In the UK we use .
instead of ,
as the decimal point - so the result of .ToString()
wouldn't match at all. But aside from that it's just bad practice to do that without a good reason.
Upvotes: 0
Reputation: 9660
In direct answer to your question, can you do this? Yes. Is it a valid approach? Almost certainly not.
If you give some more context, you will get more detailed answers.
Upvotes: 0