Double Precision - c#

I have a code, and I do not understand it. I am developing an application which precision is very important. but it does not important for .NET, why? I don't know.
double value = 3.5;
MessageBox.Show((value + 1 * Math.Pow(10, -20)).ToString());
but the message box shows: 3.5
Please help me, Thank you.

If you're doing anything where precision is very important, you need to be aware of the limitations of floating point. A good reference is David Goldberg's "What Every Computer Scientist Should Know About Floating-Point Arithmetic".
You may find that floating-point doesn't give you enough precision and you need to work with a decimal type. These, however, are always much slower than floating point -- it's a tradeoff between accuracy and speed.

You can have precision, but it depends on what else you want to do. If you put the following in a Console application:
double a = 1e-20;
Console.WriteLine(" a = {0}", a);
Console.WriteLine("1+a = {0}", 1+a);
decimal b = 1e-20M;
Console.WriteLine(" b = {0}", b);
Console.WriteLine("1+b = {0}", 1+b);
You will get
a = 1E-20
1+a = 1
b = 0,00000000000000000001
1+b = 1,00000000000000000001
But Note that The Pow function, like almost everything in the Math class, only takes doubles:
double Pow(double x, double y);
So you cannot take the Sine of a decimal (other then by converting it to double)
Also see this question.

Or use the Decimal type rather than double.

The precision of a Double is 15 digits (17 digits internally). The value that you calculate with Math.Pow is correct, but when you add it to value it just is too small to make a difference.
Edit:
A Decimal can handle that precision, but not the calculation. If you want that precision, you need to do the calculation, then convert each value to a Decimal before adding them together:
double value = 3.5;
double small = Math.Pow(10, -20);
Decimal result = (Decimal)value + (Decimal)small;
MessageBox.Show(result.ToString());

Double precision means it can hold 15-16 digits. 3.5 + 1e-20 = 21 digits. It cannot be represented in double precicion. You can use another type like decimal.

Related

Compound Interest Calculation

I have this C# code which calculate compound interest plus principal amount every year.
static void CompoundInterest(double principal, double interestRate, double years, double annualCompound)
{
var total = 0.0;
for (int t = 1; t < years + 1; t++)
{
total = principal * Math.Pow((1 + interestRate / annualCompound),
(annualCompound * t));
Console.Write("Your Total for Year {0} "
+ "is {1}. \n", t, total);
}
}
When I tested it with
CompoundInterest(1000, 0.05, 3, 12);
and the output is
Your Total for Year 1 is 1051.161897881733.
Your Total for Year 2 is 1104.941335558327.
Your Total for Year 3 is 1161.4722313334678.
How should I round it accurately? Another question is Math.Pow uses double but in financial calculation, we need decimal. How do I fix this? Convert into decimal after Math.Pow?
I made some test by rounding first and converting to decimal and by converting to decimal and then rounding afterword. Both gave the same results.
But from the logic point of view, I would convert first than rounding after words. This way I will have better control of testing what is converted and what is rounded.
For converting there are different answers, but I found this method Convert.ToDecimal is supported by all .net frameworks and cores.
ex. decimal value = Convert.ToDecimal(double_value);
And then you decimal.Round, which some one has asked and got answer here Why does .NET use banker's rounding as default?
Just in case reference to Floating-point numeric types.
You can convert a double to a decimal directly if you'd like
decimal decimalTotal = (decimal)total;
As for rounding, there is a built-in function, Math.Round, that takes a variety of number formats. It has a overload to specify how many decimal points you want.
decimal roundedDecimal = Math.Round(decimalTotal, 2);

Decimal and double values are resolving to zero [duplicate]

How do I divide two integers to get a double?
You want to cast the numbers:
double num3 = (double)num1/(double)num2;
Note: If any of the arguments in C# is a double, a double divide is used which results in a double. So, the following would work too:
double num3 = (double)num1/num2;
For more information see:
Dot Net Perls
Complementing the #NoahD's answer
To have a greater precision you can cast to decimal:
(decimal)100/863
//0.1158748551564310544611819235
Or:
Decimal.Divide(100, 863)
//0.1158748551564310544611819235
Double are represented allocating 64 bits while decimal uses 128
(double)100/863
//0.11587485515643106
In depth explanation of "precision"
For more details about the floating point representation in binary and its precision take a look at this article from Jon Skeet where he talks about floats and doubles and this one where he talks about decimals.
cast the integers to doubles.
Convert one of them to a double first. This form works in many languages:
real_result = (int_numerator + 0.0) / int_denominator
var firstNumber=5000,
secondeNumber=37;
var decimalResult = decimal.Divide(firstNumber,secondeNumber);
Console.WriteLine(decimalResult );
var result = decimal.ToDouble(decimal.Divide(5, 2));
I have went through most of the answers and im pretty sure that it's unachievable. Whatever you try to divide two int into double or float is not gonna happen.
But you have tons of methods to make the calculation happen, just cast them into float or double before the calculation will be fine.
The easiest way to do that is adding decimal places to your integer.
Ex.:
var v1 = 1 / 30 //the result is 0
var v2 = 1.00 / 30.00 //the result is 0.033333333333333333
In the comment to the accepted answer there is a distinction made which seems to be worth highlighting in a separate answer.
The correct code:
double num3 = (double)num1/(double)num2;
is not the same as casting the result of integer division:
double num3 = (double)(num1/num2);
Given num1 = 7 and num2 = 12:
The correct code will result in num3 = 0.5833333
Casting the result of integer division will result in num3 = 0.00

Imitate Math.Round for GnuMP library in C#

I downloaded for myself GnuMP library: https://gnumpnet.codeplex.com/ which behind the curtains uses gmp.dll which is wrapper for https://gmplib.org.
It has type Real, which is used for high precision calculations. In other project I have double and decimal type, which I want to replace with Real.
I need to replace Math.Round() with customized round for Real ( type in gnump.net). Did anybody tried to implement Round but for Real of Gnump.
Today I found an mathematically correct answer:
public static Real Round(Real r, int precision)
{
Real scaled = Real.Pow(10, precision + 1);
Real multiplied = r*scaled;
Real truncated = Trunc(multiplied);
Real lastNumber = truncated - Trunc(truncated/10)*10;
if (lastNumber >= 5)
{
truncated += 10;
}
truncated = Trunc(truncated/10);
return truncated * 10 /(scaled);
}
When I say mathematically correct I mean that following code:
Real r = 2.5;
r = Real.Round(r, 0);
will give 3. According to http://msdn.microsoft.com/en-us/library/wyk4d9cy.aspx Math.Round will give "round to even" (so called banker's rounding), but I for my task need mathematical round.

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).

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