Float is converting my values - c#

I have a method that tests a value is within the range allowed on fields. If it is outside the range returns null and if inside returns the value.
internal float? ExtractMoneyInRangeAndPrecision(string fieldValue, string fieldName, float min, float max, int scale, int lineNumber)
{
float returnValue;
//Check whether valid float if
if (float.TryParse(fieldValue, out returnValue))
{
//Check whether in range
if (returnValue >= min && returnValue <= max)
{
int decPosition = 0;
decPosition = fieldValue.IndexOf('.');
if (
(decPosition == -1) ||
((decPosition != -1) && (fieldValue.Substring(decPosition, fieldValue.Length - decPosition).Length -1 <= scale))
)
{
return returnValue;
}
}
}
return null;
}
Here is my unit test:
[TestMethod()]
[DeploymentItem("ImporterEngine.dll")]
public void ExtractMoneyInRangeAndPrecisionTest_OutsideRange()
{
MockSyntaxValidator target = new MockSyntaxValidator("", 0);
string fieldValue = "1000000";
string fieldName = "";
float min = 1;
float max = 999999.99f;
int scale = 2;
int lineNumber = 0;
float? Int16RangeReturned;
Int16RangeReturned = target.ExtractMoneyInRangeAndPrecision(fieldValue, fieldName, min, max, scale, lineNumber);
Assert.IsNull(Int16RangeReturned);
}
As you can see the max is 999999.99 but when the method takes it in it changes it to 1,000,000
Why is this?

http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems
In short, because of the way floating-point numbers represent real numbers, the number you assign to a float is not always the number you get back out. The value you specify is converted to the nearest value that can be represented in scientific notation with a magnitude determined by a base of 2.
In the case of 999999.99, the nearest number that can be represented as a float with the same number of sig figs is 7.6293945 * 217 = 999999.99504, which when rounded to the same sig figs is 1,000,000.00. This may not be the EXACT case, but error like this is inherent in the use of floats.
Do not use floating-point types in situations where the accuracy of the number at a given level of precision is required. Instead, use the decimal type, which will retain the precision of values entered.

Not every string of digits can be converted to a float. Without checking, I would say that 999999.99 is one such number. A decimal would solve this.

The float type doesn't have enough precision to do what you want to do. I would recommend using the decimal type. Floats can be accurate to 7 decimal digits at most, and you're using 8 here. Decimal can have up to 28 digits, which is more than enough for any amount. Moreover, unlike float, the value the compiler uses and the value you write will always be the same.
Here's the long explanation:
Floats (single-precision floating-point numbers) are stored as an integer times a power of two, where the integer is in a certain range (between 2^23 and 2^24).
When you write a decimal number in your code, the compiler interprets this as the number in this form that is closest to the number you wrote. Sometimes the match is exact (99999.75). In other cases, your number needs to be rounded to the closest floating-point number. This is what happened here:
99999.99 = 2^19 * 1.907348613739013671875
= 2^19 * 2^-23 * (2^23 * 1.907348613739013671875)
= 2^-4 * 15999999.84
The closest integer to 15999999.84 is 16000000, so the rounded value is
(float)99999.99 = 2^-4 * 16000000
= 1000000
The big advantage of the decimal type is that is represented as a 96 bit integer times a power of 10, so decimal numbers with up to 28 digits can be represented exactly, without any rounding. What you see is what you get.
The biggest disadvantage of decimal is that it is significantly slower, but in a situation like this where you're converting strings to numbers, this is not a factor.

Floating-point types (as defined in C#) are approximate. For precision you should always use decimal.
From MSDN:
The decimal keyword indicates a 128-bit data type. Compared to floating-point types, the decimal type has more precision and a smaller range, which makes it appropriate for financial and monetary calculations. The approximate range and precision for the decimal type are shown in the following table.
http://msdn.microsoft.com/en-us/library/364x0z75.aspx
There seems to be some dispute about what qualifies as a floating-point type in C#. While decimal does qualify as a floating-point type by actual definition, it is not defined as such according to the MSDN specification.
http://msdn.microsoft.com/en-us/library/9ahet949.aspx

Related

How to check input double value contain how many digits?

I need a double value to contain 2 digits after ".", such as 2.15, 20.15. If the input value is 3.125, then it should print an error message.
My code is:
private static bool isTwoDigits(double num)
{
return (num - Math.Floor(num)).ToString().Length <= 4;
}
If you input 2.15, then it will be 2.15 -2 = 0.15 <= 4 - which works. But when I change num to 20.15 it doesn't, because (num - Math.Floor(num)) here will return 0.14999999999.
Any other good ideas?
This is the nature of binary floating points number. Just like 1/3 can't be exactly written out as a finite decimal number, 0.1 can't be exactly represented by a finite binary expansion.
So depending on what you are trying to achieve exactly, you could:
If you are validating some string input (e.g. a textbox), you can process the information at the string level, e.g. with a RegEx.
You can store your numbers in the decimal datatype, which can store decimal values exactly.
You can do your computation on a double but you have to give yourself a tolerance. If you expect only 2 digits of precision, you can do something like Math.Abs(x - Math.Round(x, 2)) < 0.00000001). The definition of this tolerance margin depends on your use case.
If you're really worried about the number of decimal places, on a base-10 number, use decimal instead of double.
the decimal is for calculating financial calculations, and the reason it's called decimal in the first place is so that it can better handle base-10 calculations such as dollars and cents.
And you can also check if the number is 2 digits a bit more simply.
return num % 0.01m == 0.0m;
SO as has already been said, you can use regexp to ensure the entire format is correct.
But if you know there will only be 1 decimal because its already a number you can also just use String.IndexOf
eg
double foo = .... ;
string fooString = foo.ToString();
if (fooString.Length - fooString.IndexOf(".") != 3) => error.
(Its 3 because Length is max index + 1 )

Float wrong calculation [duplicate]

This question already has answers here:
Why am I getting the wrong result when using float? [duplicate]
(4 answers)
Float is converting my values
(4 answers)
Closed 9 years ago.
The result must be 806603.77 but why I get 806603.8 ?
float a = 855000.00f;
float b = 48396.23f;
float res = a - b;
Console.WriteLine(res);
Console.ReadKey();
You should use decimal instead because float has 32-bit with 7 digit precision only that is why the result differs, on other hand decimal has 128-bit with 28-29 digit precision.
decimal a = 855000.00M;
decimal b = 48396.23M;
decimal res = a - b;
Console.WriteLine(res);
Console.ReadKey();
Output: 806603.77
A float (also called System.Single) has a precision equivalent to approximately seven decimal figures. Your res difference needs eight significant decimal digits. Therefore it is to be expected that there is not enough precision in a float.
ADDITION:
Some extra information: Near 806,000 (806 thousand), a float only has four bits left for the fractional part. So for res it will have to choose between
806603 + 12/16 == 806603.75000000, and
806603 + 13/16 == 806603.81250000
It chooses the first one since it's closest to the ideal result. But both of these values are output as "806603.8" when calling ToString() (which Console.WriteLine(float) does call). A maximum of 7 significant decimal figures are shown with the general ToString call. To reveal that two floating-point numbers are distinct even though they print the same with the standard formatting, use the format string "R", for example
Console.WriteLine(res.ToString("R"));
Because float has limited precision (32 bits). Use double or decimal if you want more precision.
Please be aware that just blindly using Decimal isn't good enough.
Read the link posted by Oded: What Every Computer Scientist Should Know About Floating-Point Arithmetic
Only then decide on the appropriate numeric type to use.
Don't fall into the trap of thinking that just using Decimal will give you exact results; it won't always.
Consider the following code:
Decimal d1 = 1;
Decimal d2 = 101;
Decimal d3 = d1/d2;
Decimal d4 = d3*d2; // d4 = (d1/d2) * d2 = d1
if (d4 == d1)
{
Console.WriteLine("Yay!");
}
else
{
Console.WriteLine("Urk!");
}
If Decimal calculations were exact, that code should print "Yay!" because d1 should be the same as d4, right?
Well, it doesn't.
Also be aware that Decimal calculations are thousands of times slower than double calculations. They are not always suitable for non-currency calculations (e.g. calculating pixel offsets or physical things such as velocities, or anything involving transcendental numbers and so on).

Decimal precision when multiplying

Given 2 values like so:
decimal a = 0.15m;
decimal b = 0.85m;
Where a + b will always be 1.0m, both values are only specified to 2 decimal places and both values are >= 0.0m and <= 1.0m
Is it guaranteed that x == total will always be true, for all possible Decimal values of x, a and b? Using the calculation below:
decimal x = 105.99m;
decimal total = (x * a) + (x * b);
Or are there cases where x == total only to 2 decimal places, but not beyond that?
Would it make any difference if a and b could be specified to unlimited decimal places (as much as Decimal allows), but as long as a + b = 1.0m still holds?
Decimal is stored as a sign, an integer, and an integer exponent for the number 10 that represents the decimal location. So long as your integral portion of the number (e.g. 105 in 105.99) is not sufficiently large, then a + b will always equal one. and the outcome of your equation (x * a) + (x * b) will always have the correct value for the four decimal places.
Unlike float and double, precision is not lost up to the size of the data type (128 bits)
From MSDN:
The Decimal value type represents decimal numbers ranging from
positive 79,228,162,514,264,337,593,543,950,335 to negative
79,228,162,514,264,337,593,543,950,335. The Decimal value type is
appropriate for financial calculations requiring large numbers of
significant integral and fractional digits and no round-off errors.
The Decimal type does not eliminate the need for rounding. Rather, it
minimizes errors due to rounding. For example, the following code
produces a result of 0.9999999999999999999999999999 rather than 1
decimal dividend = Decimal.One;
decimal divisor = 3;
// The following displays 0.9999999999999999999999999999 to the console
Console.WriteLine(dividend/divisor * divisor);
The maximum precision of decimal in the CLR is 29 significant digits. When you're using that kind of precision, you're really talking approximation especially if you do multiplication because that requires intermediate results that the CLR must be able to process (see also http://msdn.microsoft.com/en-us/library/364x0z75.aspx).
If you have x with 2 significant digits and, say, a with 20 significant digits, then x * a will already have a minimum precision of 22 digits, and possibly more may be needed for intermediate results.
If x always has only 2 significant digits and you can keep the number of significant digits in a and b low enough (say, 22 digits -- pretty good and probably far enough away from 27 to deal with rounding errors), then I suppose (x * a) + (x * b) should be a pretty precise calculation always.
Finally, whether a + b always makes up 1.0m is of no significance related to a and b's individual precisions.

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

C# - Truncating after a position

I have a double typed variable. This variable stores information that is part of a more complex formula. Importantly, this variable can only include information up to the tenths location, or one decimal position (i.e. 10.1, 100.2, etc). However, when determining this value, it must be calculated such that anything past the tenths location is truncated, not rounded. For instance:
if the value equals 10.44, The variable value should be 10.4.
if the value equals 10.45, The variable value should also be set to 10.4
How do I truncate values in C# with respect to a decimal place?
Using an extension method:
public static double RoundDown(this double value, int digits)
{
int factor = Math.Pow(10,digits);
return Math.Truncate(value * factor) / factor;
}
Then you simply use it like this:
double rounded = number.RoundDown(2);
You have to do that by your own:
public static decimal Truncate(decimal value, int decimals)
{
if ((decimals < 0) || (decimals > 28))
{
throw new ArgumentOutOfRangeException("decimals", "The number of fractional decimals must be between 0 and 28.");
}
decimal integral = Math.Truncate(value);
decimal fractional = value - integral;
decimal shift = (decimal)Math.Pow(10, decimals);
fractional = Math.Truncate(shift * fractional);
fractional = fractional / shift;
return (integral + fractional);
}
System.Math.Truncate (d * 10) / 10
Generally, if you're working with numbers where the precise decimal representation is important, you should use decimal - not double.
With decimal, you can do something like...
decimal d = ...;
d = decimal.Truncate(d*10)/10;
If you use a double value, your truncated number will not generally be precisely representable - you may end up with excess digits or minor rounding errors. For example Math.Truncate((4.1-4.0)*10) is not 1, but 0.
While I would probably use Phillippe's answer, if you wanted to avoid scaling the number up (unlikely to be a problem for 1dp), you could:
public static double RoundDown(this double x, int numPlaces)
{
double output = Math.Round(x, numPlaces, MidpointRounding.AwayFromZero);
return (output > x ? output - Math.Pow(10, -numPlaces) : output);
}

Categories

Resources