So I was dinking around in LinqPad and noticed something odd, I get same result in Visual Studio testing code Unit Tests.
I was playing with all the different TryParse for the numerical datatypes. During this I noticed that double.TryParse is acting a bit different then the rest.
For example:
var doubleStr = double.MinValue.ToString();
//doubleStr = -1.79769313486232E+308
double result;
var result = double.TryParse(doubleStr, out result);
//result is returning false
All other datatypes with the MinValue are not having this trouble:
var floatStr = float.MinValue.ToString();
//floatStr = -3.402823E+38
float result2;
float.TryParse(floatStr, out result2);
//result = True
Any body know why double is the only one that false to parse the string version of it's MinValue property back to an actual double?
I am not seeing why this is different off hand. Maybe I am missing something.
To get a string that can be surely re-parsed as a double, use the "R" (round-trip) format string:
double.Parse(double.MinValue.ToString("R"))
In other formats, the string you get may generally re-parse to a different value, due to rounding. With double.MinValue, this gets especially worse, since the different value it would re-parse to is outside of the range of double. Hence the parse failing.
Related
Hello I'm making a quiz app and I want to compare user answers to the correct answers. I'm planning to do that with two string lists as I collect the answers in strings and I also have the correct answers in strings.
The problem that I'm facing is that half of the questions are True/False questions so the answers are in "True" or "False" strings, the other half are questions where a calculation has to be performed, therefore the answer is a number/double which I store as a string.
I want to give a range of answer acceptance of 0.1 so if the correct answer is 22.5 an answer of 22.6 would still be considered correct. This, however, makes it impossible to compare the value of the "number" strings with the Equals() method.
So I'm ideally looking for an if statement where I want to say:
if the element is convertible to a double convert it and check if its value is the same as the correct answer or within the acceptance range
else, check if the element is equal to the correct answer
For now I have made a console app to try and solve this problem where I have defined the two lists which look like this:
static void Main(string[] args)
{
List<string> givenAnswers = new List<string>()
{
"True","False","True","False","True",
"60","50","2.321","0.8","1.55"
};
List<string> correctAnswers = new List<string>()
{
"True","False","False","True","False",
"70","20","1.231","0.5","1.25"
};
correctAnswers.ForEach(Console.WriteLine);
Console.ReadLine();
}
The main problem is that c# doesnt return false if the element is not convertible but gives error which breaks the program.
(I was previously making the comparison on my frontend - java script where an unsuccessful conversion would return false)
Let's extract a method to compare two answers:
private static bool IsCorrectAnswer(string answer,
string expectedAnswer,
double tolerance = 0.1) {
// Let's not be peevish and tolerate leading / trimming spaces,
// ignore cases i.e. let " TRUE " be equal to "True"
if (string.Equals(answer?.Trim(),
expectedAnswer?.Trim(),
StringComparison.OrdinalIgnoreCase))
return true;
// If we have two double values, let's to parse them and compare
// with provided tolerance
if (double.TryParse(answer, out var leftValue) &&
double.TryParse(expectedAnswer, out var rightValue))
return Math.Abs(leftValue - rightValue) <= tolerance;
//TODO: you may want to add support for other types (say, dates) here
return false;
}
I didn't get your string list of booleans and numbers, but the general check would look like this:
foreach (var answer in givenAnswers)
{
if (double.TryParse(answer, NumberStyles.Any, CultureInfo.InvariantCulture, out double answerVal) && answerVal == 0.8)
{
Console.WriteLine("Nailed it!");
}
}
I had to use "invariant culture" because in my country, 0.8 is written as "0,8" and thus "0.8" is parses to 8...
I wouldn't go into lengths about the "nearby" numbers, because it's very complicated. Comparing Floating Point Numbers, 2012 Edition
You can use double.TryParse to check if a string is parsable to a double and parse it at the same time when it is.
bool IsAcceptableAnswser(string givenAnswer, string correctAnswer)
{
if (double.TryParse(correctAnswer, out var correctNumber) && double.TryParse(givenAnswer, out var givenNumber))
{
// When the answers are doubles, use use the double values.
var diff = Math.Abs(correctNumber - givenNumber);
return diff <= 0.1;
}
else
{
// When the answers aren't doubles, use string.Equals.
return string.Equals(givenAnswer, correctAnswer);
}
Notes
I used string.Equals for simplicity, but you could of course use something else to be more permissive around casing.
You might also want to check the other overloads of double.TryParse if culture is an issue.
I used 0.1 directly for readability. It would be preferable to use a constant or receive it as parameter.
Try:
var convertible = int.TryParse("60", out_)
I am writing unit tests that verify calculations in a database and there is a lot of rounding and truncating and stuff that mean that sometimes figures are slightly off.
When verifying, I'm finding a lot of times when things will pass but say they fail - for instance, the figure will be 1 and I'm getting 0.999999
I mean, I could just round everything into an integer but since I'm using a lot of randomized samples, eventually i'm going to get something like this
10.5
10.4999999999
one is going to round to 10, the other will round to 11.
How should I solve this problem where I need something to be approximately correct?
Define a tolerance value (aka an 'epsilon' or 'delta'), for instance, 0.00001, and then use to compare the difference like so:
if (Math.Abs(a - b) < delta)
{
// Values are within specified tolerance of each other....
}
You could use Double.Epsilon but you would have to use a multiplying factor.
Better still, write an extension method to do the same. We have something like Assert.AreSimiliar(a,b) in our unit tests.
Microsoft's Assert.AreEqual() method has an overload that takes a delta: public static void AreEqual(double expected, double actual, double delta)
NUnit also provides an overload to their Assert.AreEqual() method that allows for a delta to be provided.
You could provide a function that includes a parameter for an acceptable difference between two values. For example
// close is good for horseshoes, hand grenades, nuclear weapons, and doubles
static bool CloseEnoughForMe(double value1, double value2, double acceptableDifference)
{
return Math.Abs(value1 - value2) <= acceptableDifference;
}
And then call it
double value1 = 24.5;
double value2 = 24.4999;
bool equalValues = CloseEnoughForMe(value1, value2, 0.001);
If you wanted to be slightly professional about it, you could call the function ApproximatelyEquals or something along those lines.
static bool ApproximatelyEquals(this double value1, double value2, double acceptableDifference)
I haven't checked in which MS Test version were added but in v10.0.0.0 Assert.AreEqual methods have overloads what accept a delta parameter and do approximate comparison.
I.e.
https://msdn.microsoft.com/en-us/library/ms243458(v=vs.140).aspx
//
// Summary:
// Verifies that two specified doubles are equal, or within the specified accuracy
// of each other. The assertion fails if they are not within the specified accuracy
// of each other.
//
// Parameters:
// expected:
// The first double to compare. This is the double the unit test expects.
//
// actual:
// The second double to compare. This is the double the unit test produced.
//
// delta:
// The required accuracy. The assertion will fail only if expected is different
// from actual by more than delta.
//
// Exceptions:
// Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException:
// expected is different from actual by more than delta.
public static void AreEqual(double expected, double actual, double delta);
In NUnit, I like the clarity of this form:
double expected = 10.5;
double actual = 10.499999999;
double tolerance = 0.001;
Assert.That(actual, Is.EqualTo(expected).Within(tolerance));
One way to compare floating point numbers is to compare how many floating point representations that separate them. This solution is indifferent to the size of the numbers and thus you don't have to worry about the size of "epsilon" mentioned in other answers.
A description of the algorithm can be found here (the AlmostEqual2sComplement function in the end) and here is my C# version of it.
UPDATE:
The provided link is outdated. The new version which includes some improvements and bugfixes is here
public static class DoubleComparerExtensions
{
public static bool AlmostEquals(this double left, double right, long representationTolerance)
{
long leftAsBits = left.ToBits2Complement();
long rightAsBits = right.ToBits2Complement();
long floatingPointRepresentationsDiff = Math.Abs(leftAsBits - rightAsBits);
return (floatingPointRepresentationsDiff <= representationTolerance);
}
private static unsafe long ToBits2Complement(this double value)
{
double* valueAsDoublePtr = &value;
long* valueAsLongPtr = (long*)valueAsDoublePtr;
long valueAsLong = *valueAsLongPtr;
return valueAsLong < 0
? (long)(0x8000000000000000 - (ulong)valueAsLong)
: valueAsLong;
}
}
If you'd like to compare floats, change all double to float, all long to int and 0x8000000000000000 to 0x80000000.
With the representationTolerance parameter you can specify how big an error is tolerated. A higher value means a larger error is accepted. I normally use the value 10 as default.
The question was asking how to assert something was almost equal in unit testing. You assert something is almost equal by using the built-in Assert.AreEqual function. For example:
Assert.AreEqual(expected: 3.5, actual : 3.4999999, delta:0.1);
This test will pass. Problem solved and without having to write your own function!
FluentAssertions provides this functionality in a way that is perhaps clearer to the reader.
result.Should().BeApproximately(expectedResult, 0.01m);
I'm trying to convert the string "127.0" to an integer.
I tried this function:
int getInt(string numStr)
{
int result;
int.TryParse(numStr, out result);
return result;
}
But when I call it as int x = getInt("127.0"); then int.TryParse() sets result to 0.
When I rewrite the function like this:
int getInt(string numStr)
{
result=Convert.ToInt32(numStr);
return result;
}
the same getInt() call throws this exception:
Input string was not in a correct format.
The issue here is that "127.0" is not an integer, it's a floating point number. You will need to parse it using one of the other floating point types (i.e. double, float, Decimal, etc.).
You may want to consider either stripping off any values after the decimal point and attempting to parse it, or parsing it as another type and casting it as an integer :
int result = (int)Convert.ToDouble("1.270");
You could also take advantage of the Math.Truncate() function which would give you the integer portion of your value :
int result = (int)Math.Truncate(Convert.ToDouble("127.0"));
First off, you need to check the return value of int.TryParse(). If it returns false, then the string could not be converted.
Had you done that, you would see it returned false because 127.0 does not describe an integer value (it describes a floating point value).
Note that decimal.TryParse() would succeed here. You need to figure out if you need an integer or floating point value, and reject data that is incorrect.
An int cannot contain a decimal point; that makes it either a double, a float, or a decimal. Try to pull the number minus anything from the decimal point over to the right, like this:
int getInt(string numStr)
{
int result;
string[] splitup;
string number;
if (numstr.Contains('.'))
{
splitup = numstr.Split('.');
number = splitup[0];
int.TryParse(number, out result);
}
else
{
int.TryParse(numstr, out result);
}
return result;
}
Rion Williams is absolutely correct, IMHO.
Along with the fact that what you are parsing is not an integer, I'd personally use the TryParse method. Many of the .NET types have it, and it's quite a bit "safer" (it won't throw exceptions) than just parsing a string.
Example:
string stringValue = "127.0";
int intValue;
if(Int32.TryParse(stringValue, out intValue))
{
// return value
}
// handle the failure
If you don't like that, I'd wrap it in a try-catch...
I'm trying to parse user entered text into a float so that I can perform some wicked awesome math on the result. The result being the numberA variable at the end there. This is how I'm parsing the string into a float:
numberAString = GUI.TextField(new Rect(25, 100, 100, 25), numberAString.ToString());
bool ParsableCheckA = float.TryParse(numberAString, out numberA);
I eventually multiply numberA by another float later. I'm handling text that won't parse with a simple error message later. Couple things that bug me:
1) Why do I need to use numberAString in the TryParse parameters instead of its value? Why can't I just drop GUI.Textfield etc. into that slot? Why do I need to break this up over two lines of code?
2) I get a warning that I never use ParsableCheckA (which is true). But without it, I can't seem to use that Tryparse helper, no? Is there a way to eliminate the need for that bool? Thanks.
TryParse() Metod and its usage is rather straighforward, as shown in the following example:
double _dblOriginal;
_dblOriginal=3.141592;
string _str;
_str = _dblOriginal.ToString();
double _dblParsed;
bool _parseOK= TryParse(_str, out dblParsed);
More details in: http://msdn.microsoft.com/en-us/library/system.double.tryparse%28v=vs.110%29.aspx
Note: make sure that in your example the string numberAString you pass to the TryParse() method contains a valid number.
Also, FYI: TryParse() method has some performance benefits compare to just Parse() method because it does not throw an exception if parsing fail (instead you just check the bool result value).
Hope this will help. Regards,
(1) numberAString (see GUI.TextField) is a string, so you can use it directly in the TryParse() call.
(2) TryParse() is designed to return a boolean value so you can check for errors and take action. However, you aren't required to assign the return value. You can us it like this and simply accept the default value (0.0) assigned to the out parameter:
float.TryParse(numberAString, out numberA);
In this case you would not be able to distinguish between an invalid entry and a value that parsed correctly as zero.
I personally create an extension method to make my number parsing easier. If performance is critical, then this may not be a good idea (because for valid floats, you'll be essentially converting them twice). But I don't the effect on performance is much more than negligible.
public static class NumberExtensions
{
//Test if the text represents a valid float.
public static bool IsFloat(this string text)
{
float dummy = 0;
return Float.TryParse(text, out dummy);
}
//Convert the text to a float. Will throw exception if it's not a valid float.
public static float ToFloat(this string text)
{
float number = Float.Parse(text);
return number;
}
}
Usage...
string text = "123";
if(text.IsFloat())
{
//text must be a valid float
float myfloat = text.ToFloat();
}
else
{
//text isn't a valid float
}
You have to remember to test if it's a float by calling the IsFloat() extension method, but it's much easier for me to think of it conceptually like this rather than using out variables, which some think is a bad idea.
I have following section of code in my program:
object val;
val = arr[1].Trim(); // in my case i am getting value here is 1.00
now when I am assigning value to a datarow I am getting error
Expected int64 value.
datarow[Convert.ToString(drow["col"]).Trim().ToUpper()] = val;
I am not facing any issue when getting value other that 1.00.
What could be the exact problem? How can I solve it?
Suggestions and solutions are welcome
If that column in your datatable is expecting an Int64 you need to convert val (which is a string) to an Int64:
var val = arr[1].Trim(); // String at this point
long longVal = 0;
if(!long.TryParse(val,out longVal){
throw new InvalidOperationException("value wasnt an Int64!");
}
datarow[Convert.ToString(drow["col"]).Trim().ToUpper()] = longVal
arr[1] seems to be string, and applying .Trim() keeps it as a string, even if it's "1.00". If you need an integer, you need to parse it. However, it can't be parsed to an intteger, because it's actually a double.
As a proof of whether I'm right or not, you can try (Int64)double.Parse(val) and that should work. However, it's up to you to decide whether that's not an issue for your program. There's two possible issues:
val might not be parse-able to double, in which case you will get an exception
val might be a double, but not one that can be represented as an int (too large, or lose precision ex. "1.8" would become 1)
Hope this helps