I assign 2097151.3 to the float variable and the application prints only the integer part. Possible bug?
public static void Main(string[] args)
{
float foo = 2097151.3F;
Console.WriteLine(foo); // prints 2097151
Console.ReadKey();
}
I'm running a .NET Core console application.
Nope. Floating point numbers have been around since the 1940s. A float is only really good for 7 significant figures.
The nearest float to 2097151.3 is 2097151.25, and WriteLine is clever enough to know that and so it truncates accordingly.
If you want precise decimal values then use a decimal type.
Related
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);
This question already has answers here:
C# casting double to float error [duplicate]
(2 answers)
Closed 3 years ago.
I've just started working with C# and Visual Studio for college, and I'm struggling with using the Math.Ceiling in order to have a float value round up to the next integer before it's outputted.
Visual Studio says I'm missing a cast, but I don't really know where. It's probably really simple, but being new I don't really know where to start.
The final line shown is where I've got a problem.
I could just do with someone telling me where I'm going wrong here.
I tried using a float.Parse around the Math.Ceiling but that doesn't work apparently
const float FencePanelWidth = 1.5f;
float GWidth;
float GLength;
float GPerimetre;
float FencePanelsNeed;
float FencePanelsNeed2;
Console.Write("");
Console.Write("");
GWidth = float.Parse(Console.ReadLine());
Console.Write("");
GLength = float.Parse(Console.ReadLine());
GPerimetre = (GLength * 2) + GWidth;
FencePanelsNeed = GPerimetre / FencePanelWidth;
FencePanelsNeed2 = Math.Ceiling(FencePanelsNeed);
If FencePanelsNeed was say 7.24, I'd want FencePanelsNeed2 to be 8.
The Math.Ceiling method has only two overloads:
public static decimal Ceiling (decimal d); - Docs.
public static double Ceiling (double a); - Docs.
In your case, it uses the second overload (because the passed float value gets casted to double, and therefore, returns a double.
What you should do is cast the returned value to int or float:
FencePanelsNeed2 = (int)Math.Ceiling(FencePanelsNeed); // Or:
//FencePanelsNeed2 = (float)Math.Ceiling(FencePanelsNeed);
If you cast it to an int, you might also declare your FencePanelsNeed2 as int instead of float.
Note that if FencePanelsNeed2 were declared as double, you wouldn't get that error in the first place because no cast would be needed. So, it only comes down to which type you want to use.
Just cast it to an int and add 1, will always work
using System;
public class Program
{
const float FencePanelWidth = 7.24f;
public static void Main()
{
var FencePanelsNeed2 = (int)FencePanelWidth < FencePanelWidth ? (int)FencePanelWidth + 1 : (int)FencePanelWidth;
Console.WriteLine(FencePanelsNeed2);
}
}
Try it for yourself.
I just discovered MathF (wonderful tool). Like any new tool, we're going through some... growing pains. I'm working on unit conversion script. Here's my code. I thought MathF.Pow requires two floats, in this case 10 and 6. But apparently that's frowned upon. Any ideas?
Mathf megagram;
void Start () {
megagram = Mathf.Pow(10,6);
Mathf.Pow returns a float while you are assigning the return value (float) to megagram (MathF type)
float megagram;
void Start ()
{
megagram = Mathf.Pow(10f,6f);
}
If you write 6 or 10, compiler thinks that you use Int32. For floats write f suffix - 6f, 10f
Also Mathf.Pow returns float, not a Mathf type
I wrote very simple code:
public static void Main (string[] args)
{
String str="1,0992748756871115E+41"; //yes, I know that is very large value
Double x=Convert.ToDouble(str);
Double res=Math.Cos(x);
Double resRound=Math.Round(res);
Console.WriteLine("x={0}\nres={1}\nresRound={2}", x, res, resRound);
}
And this code output very large value of res value: 1,09927487568711E+41 which a equals to Math.Cos's arguments:
I thought, that is a bug of Gtk# and decided to test what value returns this code compilled by .NET Framework and it returned same value!
Is that so the meaning of the function cos(x) exceeds the limits of segment from -1 to 1? How does it possible?
From the documentation:
Acceptable values of d range from approximately -9223372036854775295 to approximately 9223372036854775295. For values outside this range, the Cos method returns d unchanged rather than throwing an exception.
You can break down the expression to get the values like
Cost(A+B)= CosA *CosB -SinA * SinB
Break down as low as you can get within the documentation limit
I am working with a Fortran program that expects floating point numbers to be input using Fortran's E format specifier, which is scientific notation, except the mantissa must be between 0 and 1. So instead of:
"3147.3" --> "3.1473E3",
it needs
"3147.3" --> "0.31473E4".
I am unable to modify the Fortran program, as it works with a few other programs that are also particular.
It would appear that the C# E format string would give me the former. Is there any simple way to achieve the latter in C#?
You could specify a custom format like so.
var num = 3147.3;
num.ToString("\\0.#####E0"); // "0.31473E4"
I think that you are solving a non-existent problem. It is true that the default of the Fortran E output specifier has a leading zero before the decimal point (this can be modified). But when the E specifier is used for input it is very tolerant and does not require the leading zero -- if you have a decimal point in the number and the number fits within the columns specified by the format, it will work.
Here is an example Fortran program, and an example input file.
program test_format
real :: num1, num2, num3
open (unit=16, file="numbers_3.txt", status='old', access='sequential', form='formatted', action='read' )
read (16, 1010 ) num1
read (16, 1010 ) num2
read (16, 1010 ) num3
1010 format (E9.5)
write (*, *) num1, num2, num3
stop
end program test_format
and the sample input with three different cases:
3.1473E3
0.31473E4
3147.3
I tested the program with gfortran and Intel ifort. The output was:
3147.300 3147.300 3147.300
So when performing input using Fortran's E format specifier, it is not necessary that the digit before the decimal point be zero. It is not even necessary that the input value use E-notation!
Edit / P.S. I translated the program to the fixed-form source layout of FORTRAN 77 and compiled it with g77 -- it read the three test numbers just fine. The E-format has been flexible for input for a long time -- probably since FORTRAN IV, perhaps longer.
The representaiton of floats or doubles are defined in IEEE754 / IEC 60559:1989. You should look to find libraries to extract mantissa and exponent. Then you could just divide by then to move to comma and subtract the number of steps from the exponent to form your solution.
You could take something similar to Jeff M's solution, and implement it via extension method:
public static class DoubleExtensions
{
public static string ToFortranDouble(this double value)
{
return value.ToString("\\0.#####E0");
}
}
class Program
{
static void Main(string[] args)
{
string fortranValue = 3147.3.ToFortranDouble();
System.Console.WriteLine(fortranValue);
}
}
Or for something a little more complicated (not sure how much precision Fortran floats/doubles give):
public static class DoubleExtensions
{
public static string ToFortranDouble(this double value)
{
return value.ToFortranDouble(4);
}
public static string ToFortranDouble(this double value, int precision)
{
return string.Format(value.ToString(
string.Format("\\0.{0}E0", new string('#', precision))
));
}
}