double and rounding is very hard, but this is crazy - c#

double a = 135.24; // a is set to 135.24000000000001 actually
double b = Math.Round(a, 0); // set to 135.0
double c = Math.Round(a, 1); // set to 135.19999999999999
double d = Math.Round(a, 2); // set to 135.24000000000001
double e = Math.Round(a, 3); // set to 135.24000000000001
double f = Math.Round(a, 4); // set to 135.24000000000001
double g = Math.Round(a, 5); // set to 135.24000000000001
double h = Math.Round(a, 10); // set to 135.24000000000001
double i = Math.Round(a, 14); // set to 135.24000000000001
double j = Math.Round(a, 2
, MidpointRounding.AwayFromZero ); // set to 135.24000000000001
double k = Math.Round(a, 2
, MidpointRounding.ToEven ); // set to 135.24000000000001
Sooooo, this means that 135.24 cannot be represented with a double, right?

Yes, 135.24 cannot be represented by double since double uses binary exponential notation.
That is: 135.24 can be represented exponentially in base of 2 as 1.0565625 * 128 = ( 1 + 1/32 + 1/64 + 1/128 + 1/1024 + ... ) * (2**7).
The representation cannot be done exactly, because 13524 does not divide by 5. Let's look:
135.24 = 13524/(10**2)
representation is finite <=> exist whole x and n satisfying 135.24 = x/(2**n)
135.24 = x/(2**n)
13524 / (10**2) = x / (2**n)
13524 * (2**n) = (10**2) * x
13524 * (2**n) = 2*2*5*5 * x
there is no "5" on the left side, so it cannot be done
(known as the Fundamental Theorem of Arithmetic)
In general, finite binary representation is exact only if there is sufficient number of "fives" in prime factorization of the decimal number.
Now the fun part:
double delta = 0.5;
while( 1 + delta > 1 )
delta /= 2;
Console.WriteLine( delta );
Precision of double is different near 1, different near 0, and different for some big numbers. Some binary representation examples on Wikipedia: Double precision floating point format
But the most important thing is that internal processor floating-point stack may have much better precision than 8 bytes (double). If number does not have to be transferred to RAM and stripped down to 8 bytes we can get a really nice precision.
Testing something like this on different processors (AMD, Intel), languages (C, C++, C#, Java) or compiler optimization levels can give results can be around 1e-16, 1e-20, or even 1e-320
Take a look at CIL / assembler / jasmin code to see exactly what is going on (eg: for C++ g++ -S test.cpp creates test.s file with assembler code in it)

That is generally a problem with floating point numbers. If you need an exact representation of numbers (e.g. for billing, ...) then you should use Decimal.
Try following piece of code and you will see that you do not have the output 0, 0.1, 0.2, ... 1.0.
for(double i = 0; i <= 1.0; i += 0.001)
{
Console.WriteLine(i);
}

Try using decimal instead. Floating points are not very precise (thus some numbers can't be represented) :)

Yes, it cannot. This is why there's another nonintegra datatype called decimal. It takes different amount of memory and has different min/max numerical ranges than double, and is NOT bit-convertible*) to double, but in turn it can held numbers precisely without any distortions.
*) That is, you cannot i.e. copy it as bytes and push to C++ code. However, you can still cast it to double and back. Just mind that the cast will NOT be precise, as double cannot hold some numbers that decimal can, and vice versa

You can see the definition.The Round function defined as-
public static double Round(double value, int digits, MidpointRounding mode)
{
if (digits < 0 || digits > 15)
throw new ArgumentOutOfRangeException("digits", Environment.GetResourceString("ArgumentOutOfRange_RoundingDigits"));
if (mode >= MidpointRounding.ToEven && mode <= MidpointRounding.AwayFromZero)
return Math.InternalRound(value, digits, mode);
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidEnumValue", (object) mode, (object) "MidpointRounding"), "mode");
}
private static unsafe double InternalRound(double value, int digits, MidpointRounding mode)
{
if (Math.Abs(value) < Math.doubleRoundLimit)
{
double num1 = Math.roundPower10Double[digits];
value *= num1;
if (mode == MidpointRounding.AwayFromZero)
{
double num2 = Math.SplitFractionDouble(&value);
if (Math.Abs(num2) >= 0.5)
value += (double) Math.Sign(num2);
}
else
value = Math.Round(value);
value /= num1;
}
return value;
}

Related

Creating a power function in C# without using Math.Pow(x, y) [duplicate]

System.Numerics.BigInteger lets you multiply large integers together, but is there anything of the same type for floating point numbers? If not, is there a free library I can use?
//this but with floats
System.Numerics.BigInteger maxint = new BigInteger(int.MaxValue);
System.Numerics.BigInteger big = maxint * maxint * maxint;
System.Console.WriteLine(big);
Perhaps you're looking for BigRational? Microsoft released it under their BCL project on CodePlex. Not actually sure how or if it will fit your needs.
It keeps it as a rational number. You can get the a string with the decimal value either by casting or some multiplication.
var r = new BigRational(5000, 3768);
Console.WriteLine((decimal)r);
Console.WriteLine((double)r);
Or with a simple(ish) extension method like this:
public static class BigRationalExtensions
{
public static string ToDecimalString(this BigRational r, int precision)
{
var fraction = r.GetFractionPart();
// Case where the rational number is a whole number
if(fraction.Numerator == 0 && fraction.Denominator == 1)
{
return r.GetWholePart() + ".0";
}
var adjustedNumerator = (fraction.Numerator
* BigInteger.Pow(10, precision));
var decimalPlaces = adjustedNumerator / fraction.Denominator;
// Case where precision wasn't large enough.
if(decimalPlaces == 0)
{
return "0.0";
}
// Give it the capacity for around what we should need for
// the whole part and total precision
// (this is kinda sloppy, but does the trick)
var sb = new StringBuilder(precision + r.ToString().Length);
bool noMoreTrailingZeros = false;
for (int i = precision; i > 0; i--)
{
if(!noMoreTrailingZeros)
{
if ((decimalPlaces%10) == 0)
{
decimalPlaces = decimalPlaces/10;
continue;
}
noMoreTrailingZeros = true;
}
// Add the right most decimal to the string
sb.Insert(0, decimalPlaces%10);
decimalPlaces = decimalPlaces/10;
}
// Insert the whole part and decimal
sb.Insert(0, ".");
sb.Insert(0, r.GetWholePart());
return sb.ToString();
}
}
If it's out of the precision range of a decimal or double, they will be cast to their respective types with a value of 0.0. Also, casting to decimal, when the result is outside of its range, will cause an OverflowException to be thrown.
The extension method I wrote (which may not be the best way to calculate a fraction's decimal representation) will accurately convert it to a string, with unlimited precision. However, if the number is smaller than the precision requested, it will return 0.0, just like decimal or double would.
It should be considered what the implications would be if there were a BigFloat type.
BigFloat x = 1.0;
BigFloat y = 3.0;
BigFloat z = x / y;
The answer would be 0.333333333333333333333333333333333333333333333333333333 recurring. Forever. Infinite. Out of Memory Error.
It is easy to construct an infinite BigFloat.
However, if you are happy to stick to rational numbers, those express by the dividing one integer with another than you can use BigInteger to build a BigRational type that can provide arbitrary precision for representing any real number.
BigRational x = 1;
BigRational y = 3;
BigRational z = x / y;
This works and gives us this type:
You can just NuGet BigRational and you'll find many implementations, including once from Microsoft.

Divide by 0 error C# [duplicate]

This simple calculation is returning zero, I can't figure it out:
decimal share = (18 / 58) * 100;
You are working with integers here. Try using decimals for all the numbers in your calculation.
decimal share = (18m / 58m) * 100m;
18 / 58 is an integer division, which results in 0.
If you want decimal division, you need to use decimal literals:
decimal share = (18m / 58m) * 100m;
Since some people are linking to this from pretty much any thread where the calculation result is a 0, I am adding this as a solution as not all the other answers apply to case scenarios.
The concept of needing to do calculations on various types in order to obtain that type as a result applies, however above only shows 'decimal' and uses it's short form such as 18m as one of the variables to be calculated.
// declare and define initial variables.
int x = 0;
int y = 100;
// set the value of 'x'
x = 44;
// Results in 0 as the whole number 44 over the whole number 100 is a
// fraction less than 1, and thus is 0.
Console.WriteLine( (x / y).ToString() );
// Results in 0 as the whole number 44 over the whole number 100 is a
// fraction less than 1, and thus is 0. The conversion to double happens
// after the calculation has been completed, so technically this results
// in 0.0
Console.WriteLine( ((double)(x / y)).ToString() );
// Results in 0.44 as the variables are cast prior to calculating
// into double which allows for fractions less than 1.
Console.WriteLine( ((double)x / (double)y).ToString() );
Because the numbers are integers and you perform integer division.
18 / 58 is 0 in integer division.
Whenever I encounter such situations, I just upcast the numerator.
double x = 12.0 / 23409;
decimal y = 12m / 24309;
Console.WriteLine($"x = {x} y = {y}");
double res= (firstIntVar * 100f / secondIntVar) / 100f;
when dividing numbers I use double or decimal , else I am getting 0 , with this code even if firstIntVar && secondIntVar are int it will return the expected answer
decimal share = (18 * 100)/58;
Solved: working perfectly with me
int a = 375;
int b = 699;
decimal ab = (decimal)a / b * 100;

Is there a BigFloat class in C#?

System.Numerics.BigInteger lets you multiply large integers together, but is there anything of the same type for floating point numbers? If not, is there a free library I can use?
//this but with floats
System.Numerics.BigInteger maxint = new BigInteger(int.MaxValue);
System.Numerics.BigInteger big = maxint * maxint * maxint;
System.Console.WriteLine(big);
Perhaps you're looking for BigRational? Microsoft released it under their BCL project on CodePlex. Not actually sure how or if it will fit your needs.
It keeps it as a rational number. You can get the a string with the decimal value either by casting or some multiplication.
var r = new BigRational(5000, 3768);
Console.WriteLine((decimal)r);
Console.WriteLine((double)r);
Or with a simple(ish) extension method like this:
public static class BigRationalExtensions
{
public static string ToDecimalString(this BigRational r, int precision)
{
var fraction = r.GetFractionPart();
// Case where the rational number is a whole number
if(fraction.Numerator == 0 && fraction.Denominator == 1)
{
return r.GetWholePart() + ".0";
}
var adjustedNumerator = (fraction.Numerator
* BigInteger.Pow(10, precision));
var decimalPlaces = adjustedNumerator / fraction.Denominator;
// Case where precision wasn't large enough.
if(decimalPlaces == 0)
{
return "0.0";
}
// Give it the capacity for around what we should need for
// the whole part and total precision
// (this is kinda sloppy, but does the trick)
var sb = new StringBuilder(precision + r.ToString().Length);
bool noMoreTrailingZeros = false;
for (int i = precision; i > 0; i--)
{
if(!noMoreTrailingZeros)
{
if ((decimalPlaces%10) == 0)
{
decimalPlaces = decimalPlaces/10;
continue;
}
noMoreTrailingZeros = true;
}
// Add the right most decimal to the string
sb.Insert(0, decimalPlaces%10);
decimalPlaces = decimalPlaces/10;
}
// Insert the whole part and decimal
sb.Insert(0, ".");
sb.Insert(0, r.GetWholePart());
return sb.ToString();
}
}
If it's out of the precision range of a decimal or double, they will be cast to their respective types with a value of 0.0. Also, casting to decimal, when the result is outside of its range, will cause an OverflowException to be thrown.
The extension method I wrote (which may not be the best way to calculate a fraction's decimal representation) will accurately convert it to a string, with unlimited precision. However, if the number is smaller than the precision requested, it will return 0.0, just like decimal or double would.
It should be considered what the implications would be if there were a BigFloat type.
BigFloat x = 1.0;
BigFloat y = 3.0;
BigFloat z = x / y;
The answer would be 0.333333333333333333333333333333333333333333333333333333 recurring. Forever. Infinite. Out of Memory Error.
It is easy to construct an infinite BigFloat.
However, if you are happy to stick to rational numbers, those express by the dividing one integer with another than you can use BigInteger to build a BigRational type that can provide arbitrary precision for representing any real number.
BigRational x = 1;
BigRational y = 3;
BigRational z = x / y;
This works and gives us this type:
You can just NuGet BigRational and you'll find many implementations, including once from Microsoft.

Division returns zero

This simple calculation is returning zero, I can't figure it out:
decimal share = (18 / 58) * 100;
You are working with integers here. Try using decimals for all the numbers in your calculation.
decimal share = (18m / 58m) * 100m;
18 / 58 is an integer division, which results in 0.
If you want decimal division, you need to use decimal literals:
decimal share = (18m / 58m) * 100m;
Since some people are linking to this from pretty much any thread where the calculation result is a 0, I am adding this as a solution as not all the other answers apply to case scenarios.
The concept of needing to do calculations on various types in order to obtain that type as a result applies, however above only shows 'decimal' and uses it's short form such as 18m as one of the variables to be calculated.
// declare and define initial variables.
int x = 0;
int y = 100;
// set the value of 'x'
x = 44;
// Results in 0 as the whole number 44 over the whole number 100 is a
// fraction less than 1, and thus is 0.
Console.WriteLine( (x / y).ToString() );
// Results in 0 as the whole number 44 over the whole number 100 is a
// fraction less than 1, and thus is 0. The conversion to double happens
// after the calculation has been completed, so technically this results
// in 0.0
Console.WriteLine( ((double)(x / y)).ToString() );
// Results in 0.44 as the variables are cast prior to calculating
// into double which allows for fractions less than 1.
Console.WriteLine( ((double)x / (double)y).ToString() );
Because the numbers are integers and you perform integer division.
18 / 58 is 0 in integer division.
Whenever I encounter such situations, I just upcast the numerator.
double x = 12.0 / 23409;
decimal y = 12m / 24309;
Console.WriteLine($"x = {x} y = {y}");
double res= (firstIntVar * 100f / secondIntVar) / 100f;
when dividing numbers I use double or decimal , else I am getting 0 , with this code even if firstIntVar && secondIntVar are int it will return the expected answer
decimal share = (18 * 100)/58;
Solved: working perfectly with me
int a = 375;
int b = 699;
decimal ab = (decimal)a / b * 100;

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