I'm working with double in C#. Double has Precision ~15-17 digits.
In my program, the user enters: 0.011 - 0.001, and the result shows 0.0099999999999999985 --> that's ugly in the user's eye - they will question my math ability.
I'm okay with the result being 0.0099999999999999985 internal, but when display, I want to find a way to fix the precision digits. For example:
double a = 0.011;
double b = 0.001;
double result, display;
result = a - b;//result = 0.0099999999999999985
display = ConvertForDisplay(result);//I want display = 0.01
I see that the build-in Android app "Calculator" on Samsung smartphone (e.g Galaxy Tab SM-T295) also use double (because I enter 10^309 and it gives error) but when I enter the math 0.011 - 0.001, it properly shows me 0.01.
I thought about Math.Round (double value, int digits), but the digits must be in range [0,15], while I also need to display the numbers like 1E-200.
I've search around the internet but I just saw questions about how to deal with the floating point accuracy problems (e.g don't use == but use Math.Abs(a-b) < double.Epsilon, Math.Round,...). But I can't find how to round the precision digits (e.g the value 0.0099999999999999985 has the precision digits 99999999999999985, when the those digits contains more than 15 "9"s, then it should be round for display).
So what is the proper way to fix this problem (e.g convert 0.0099999999999999985 into 0.01)?
Extra: when I enter 9999999999999999d, C# gives me 1E+16, I know this happens because C# sees that all the precision digits, which it can hold, is 9 so it rounds up to 10, but is there any way I can make it keeps all the 9s - I see that the Android app "Calculator", which I mention above, also gives this behavior, so I count this as extra - not a must-fix, but I want to know if it's fixable just for fun.
Update:
I see the behavior: (1.021 - 1.01) = 0.010999999999999899
But (1.021 - 1.01) + 1 = 1.011
So when I add 1, double triggers its "internal round" feature (I guess) and it rounds to the number I want. Maybe this could lead to my solution?
Here's another interesting discover: cast the value to float can also give the number I want, e.g: (float)(1.021 - 1.01) = 0.011
I re-think the issue, how about I use decimal as a tool to fix this problem. The idea is to use decimal to solve the math (if the range is suitable for decimal), then cast the decimal back to double. Here is the code:
const int LEFT = 0;
const int RIGHT = 1;
private static bool IsConvertableToDecimal(double value)
{
const double MAX = (double)decimal.MaxValue;
const double MIN = (double)decimal.MinValue;
const double EXP_MIN = -1E-28;
const double EXP_MAX = 1E-28;
return
(value >= EXP_MAX && value < MAX) ||
value == 0 ||
(value > MIN && value <= EXP_MIN);
}
private static double BasicFunc(double[] arr,
Func<double, double, double> funcDouble,
Func<decimal, decimal, decimal> funcDecima)
{
var result = funcDouble(arr[LEFT], arr[RIGHT]);
//Check if can convert to decimal for better accurancy
if (IsConvertableToDecimal(result) &&
IsConvertableToDecimal(arr[LEFT]) &&
IsConvertableToDecimal(arr[RIGHT]))
result = (double)(funcDecima((decimal)arr[LEFT], (decimal)arr[RIGHT]));
return result;
}
public static double ADD(double[] arr)
=> BasicFunc(arr, (x, y) => x + y, decimal.Add);
public static double SUBTRACT(double[] arr)
=> BasicFunc(arr, (x, y) => x - y, decimal.Subtract);
public static double MULT(double[] arr)
=> BasicFunc(arr, (x, y) => x * y, decimal.Multiply);
public static double DIV(double[] arr)
=> BasicFunc(arr, (x, y) => x / y, decimal.Divide);
//Usage ================
void Test()
{
var arr = new double[2];
arr[0] = 0.011;
arr[1] = 0.001;
var result = SUBTRACT(arr);
Print(result);//Result = 0.01 ==> Success!!!
}
Related
How can I multiply two decimals and round the result down to 2 decimal places?
For example if the equation is 41.75 x 0.1 the result will be 4.175. If I do this in c# with decimals it will automatically round up to 4.18. I would like to round down to 4.17.
I tried using Math.Floor but it just rounds down to 4.00. Here is an example:
Math.Floor (41.75 * 0.1);
The Math.Round(...) function has an Enum to tell it what rounding strategy to use. Unfortunately the two defined won't exactly fit your situation.
The two Midpoint Rounding modes are:
AwayFromZero - When a number is halfway between two others, it is rounded toward the nearest number that is away from zero. (Aka, round up)
ToEven - When a number is halfway between two others, it is rounded toward the nearest even number. (Will Favor .16 over .17, and .18 over .17)
What you want to use is Floor with some multiplication.
var output = Math.Floor((41.75 * 0.1) * 100) / 100;
The output variable should have 4.17 in it now.
In fact you can also write a function to take a variable length as well:
public decimal RoundDown(decimal i, double decimalPlaces)
{
var power = Convert.ToDecimal(Math.Pow(10, decimalPlaces));
return Math.Floor(i * power) / power;
}
public double RoundDown(double number, int decimalPlaces)
{
return Math.Floor(number * Math.Pow(10, decimalPlaces)) / Math.Pow(10, decimalPlaces);
}
As of .NET Core 3.0 and the upcoming .NET Framework 5.0 the following is valid
Math.Round(41.75 * 0.1, 2, MidpointRounding.ToZero)
There is no native support for precision floor/ceillin in c#.
You can however mimic the functionality by multiplying the number, the floor, and then divide by the same multiplier.
eg,
decimal y = 4.314M;
decimal x = Math.Floor(y * 100) / 100; // To two decimal places (use 1000 for 3 etc)
Console.WriteLine(x); // 4.31
Not the ideal solution, but should work if the number is small.
One more solution is to make rounding toward zero from rounding away from zero.
It should be something like this:
static decimal DecimalTowardZero(decimal value, int decimals)
{
// rounding away from zero
var rounded = decimal.Round(value, decimals, MidpointRounding.AwayFromZero);
// if the absolute rounded result is greater
// than the absolute source number we need to correct result
if (Math.Abs(rounded) > Math.Abs(value))
{
return rounded - new decimal(1, 0, 0, value < 0, (byte)decimals);
}
else
{
return rounded;
}
}
This is my Float-Proof Round Down.
public static class MyMath
{
public static double RoundDown(double number, int decimalPlaces)
{
string pr = number.ToString();
string[] parts = pr.Split('.');
char[] decparts = parts[1].ToCharArray();
parts[1] = "";
for (int i = 0; i < decimalPlaces; i++)
{
parts[1] += decparts[i];
}
pr = string.Join(".", parts);
return Convert.ToDouble(pr);
}
}
I've found that the best method is to use strings; the binary vagaries of Math tend to get things wrong, otherwise. One waits for .Net 5.0 to make this fact obsolete. No decimal places is a special case: you can use Math.Floor for that. Otherwise, we ToString the number with one more decimal place than is required, then parse that without its last digit to get the answer:
/// <summary>
/// Truncates a Double to the given number of decimals without rounding
/// </summary>
/// <param name="D">The Double</param>
/// <param name="Precision">(optional) The number of Decimals</param>
/// <returns>The truncated number</returns>
public static double RoundDown(this double D, int Precision = 0)
{
if (Precision <= 0) return Math.Floor(D);
string S = D.ToString("0." + new string('0', Precision + 1));
return double.Parse(S.Substring(0, S.Length - 1));
}
If you want to round down any double to specific decimal places, if doesn´t matter if is the midpoint, you can use:
public double RoundDownDouble(double number, int decimaPlaces)
{
var tmp = Math.Pow(10, decimaPlaces);
return Math.Truncate(number * tmp) / tmp;
}
Consider this:
double x,y;
x =120.0;
y = 0.05;
double z= x % y;
I tried this and expected the result to be 0, but it came out 0.04933333.
However,
x =120.0;
y = 0.5;
double z= x % y;
did indeed gave the correct result of 0.
What is happening here?
I tried Math.IEEERemainder(double, double) but it's not returning 0 either. What is going on here?
Also, as an aside, what is the most appropriate way to find remainder in C#?
Because of its storage format, doubles cannot store every values exactly as is is entered or displayed. The human representation of numbers is usually in decimal format, while doubles are based on the dual system.
In a double, 120 is stored precisely because it's an integer value. But 0.05 is not. The double is approximated to the closest number to 0.05 it can represent. 0.5 is a power of 2 (1/2), so it can be stored precisely and you don't get a rounding error.
To have all numbers exactly the same way you enter / display it in the decimal system, use decimal instead.
decimal x, y;
x = 120.0M;
y = 0.05M;
decimal z = x % y; // z is 0
You could do something like:
double a, b, r;
a = 120;
b = .05;
r = a - Math.floor(a / b) * b;
This should help ;)
I believe if you tried the same with decimal it would work properly.
http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems can help you understand why you get these "strange" results. There's a particular precision that floating point numbers can have. Just try these queries and have a look at the results:
0.5 in base 2
0.05 in base 2
Modulus should only be used with integer. The remainder come from an euclidean division. With double, you can have unexpected results.
See this article
This is what we use.. :)
public double ModuloOf(double v1, double v2)
{
var mult = 0;
//find number of decimals
while (v2 % 1 > 0)
{
mult++;
v2 = v2 * 10;
}
v1 = v1 * Math.Pow(10, mult);
var rem = v1 % v2;
return rem / Math.Pow(10, mult);
}
I want to compare two doubles a and b in C# (where for example b has more decimal places) in the way that: if I round the number b to number of decimal places of a i should get the same number if they are the same. Example:
double a = 0.123;
double b = 0.1234567890;
should be same.
double a = 0.123457
double b = 0.123456789
should be same.
I cannot write
if(Math.Abs(a-b) < eps)
because I don't know how to calculate precision eps.
If I have understood what you want you could just shift the digits before the decimal place til the "smaller" (i.e. one with least significant figures) is a integer, then compare:
i.e. in some class...
static bool comp(double a, double b)
{
while((a-(int)a)>0 && (b - (int)b)>0)
{
a *= 10;
b *= 10;
}
a = (int)a;
b = (int)b;
return a == b;
}
Edit
Clearly calling (int)x on a double is asking for trouble since double can store bigger numbers than ints. This is better:
while((a-Math.Floor(a))>0 && (b - Math.Floor(b))>0)
//...
double has epsilon double.Epsilon or set prefer error by hardcode, f.e. 0.00001
How can I multiply two decimals and round the result down to 2 decimal places?
For example if the equation is 41.75 x 0.1 the result will be 4.175. If I do this in c# with decimals it will automatically round up to 4.18. I would like to round down to 4.17.
I tried using Math.Floor but it just rounds down to 4.00. Here is an example:
Math.Floor (41.75 * 0.1);
The Math.Round(...) function has an Enum to tell it what rounding strategy to use. Unfortunately the two defined won't exactly fit your situation.
The two Midpoint Rounding modes are:
AwayFromZero - When a number is halfway between two others, it is rounded toward the nearest number that is away from zero. (Aka, round up)
ToEven - When a number is halfway between two others, it is rounded toward the nearest even number. (Will Favor .16 over .17, and .18 over .17)
What you want to use is Floor with some multiplication.
var output = Math.Floor((41.75 * 0.1) * 100) / 100;
The output variable should have 4.17 in it now.
In fact you can also write a function to take a variable length as well:
public decimal RoundDown(decimal i, double decimalPlaces)
{
var power = Convert.ToDecimal(Math.Pow(10, decimalPlaces));
return Math.Floor(i * power) / power;
}
public double RoundDown(double number, int decimalPlaces)
{
return Math.Floor(number * Math.Pow(10, decimalPlaces)) / Math.Pow(10, decimalPlaces);
}
As of .NET Core 3.0 and the upcoming .NET Framework 5.0 the following is valid
Math.Round(41.75 * 0.1, 2, MidpointRounding.ToZero)
There is no native support for precision floor/ceillin in c#.
You can however mimic the functionality by multiplying the number, the floor, and then divide by the same multiplier.
eg,
decimal y = 4.314M;
decimal x = Math.Floor(y * 100) / 100; // To two decimal places (use 1000 for 3 etc)
Console.WriteLine(x); // 4.31
Not the ideal solution, but should work if the number is small.
One more solution is to make rounding toward zero from rounding away from zero.
It should be something like this:
static decimal DecimalTowardZero(decimal value, int decimals)
{
// rounding away from zero
var rounded = decimal.Round(value, decimals, MidpointRounding.AwayFromZero);
// if the absolute rounded result is greater
// than the absolute source number we need to correct result
if (Math.Abs(rounded) > Math.Abs(value))
{
return rounded - new decimal(1, 0, 0, value < 0, (byte)decimals);
}
else
{
return rounded;
}
}
This is my Float-Proof Round Down.
public static class MyMath
{
public static double RoundDown(double number, int decimalPlaces)
{
string pr = number.ToString();
string[] parts = pr.Split('.');
char[] decparts = parts[1].ToCharArray();
parts[1] = "";
for (int i = 0; i < decimalPlaces; i++)
{
parts[1] += decparts[i];
}
pr = string.Join(".", parts);
return Convert.ToDouble(pr);
}
}
I've found that the best method is to use strings; the binary vagaries of Math tend to get things wrong, otherwise. One waits for .Net 5.0 to make this fact obsolete. No decimal places is a special case: you can use Math.Floor for that. Otherwise, we ToString the number with one more decimal place than is required, then parse that without its last digit to get the answer:
/// <summary>
/// Truncates a Double to the given number of decimals without rounding
/// </summary>
/// <param name="D">The Double</param>
/// <param name="Precision">(optional) The number of Decimals</param>
/// <returns>The truncated number</returns>
public static double RoundDown(this double D, int Precision = 0)
{
if (Precision <= 0) return Math.Floor(D);
string S = D.ToString("0." + new string('0', Precision + 1));
return double.Parse(S.Substring(0, S.Length - 1));
}
If you want to round down any double to specific decimal places, if doesn´t matter if is the midpoint, you can use:
public double RoundDownDouble(double number, int decimaPlaces)
{
var tmp = Math.Pow(10, decimaPlaces);
return Math.Truncate(number * tmp) / tmp;
}
I want a function that is passed an integer, and if that integer is over a certain value (1000 in my current case) I want to perform some division on it so I can ultimately return an abbreviation of the original integer.
For example:
1000 = 1
1001 = 1
1099 = 1
1100 = 1.1
1199 = 1.1
1200 = 1.2
10000 = 10
10099 = 10
10100 = 10.1
It's the division and rounding side of things that has been causing me problems.
What would be the most suitable method to give me the results above?
How about:
int dividedBy100 = x / 100; // Deliberately an integer division
decimal dividedBy1000 = dividedBy100 / 10m; // Decimal division
string result = dividedBy1000.ToString();
I would advise using decimal here rather than float or double, as you fundamentally want decimal division by 10.
An abbreviation is by definition rounded.
If you are looking for more precision why not use Double instead of Integer?
Here's a suggestion
double function(int number)
{
if (number >= 1000)
{
return (((double)number) / 1000);
}
}
Your examples seem to imply that you only want one decimal place of precision, so how about something like this:
Divide by 100
Cast to double (or float)
Divide by 10
The first division will truncate any trailing numbers less than 100 (the equivalent of a 100-base floor function), then casting to double and dividing by 10 will give you the single decimal place of precision you want.
if t is the original number, then
int a=t/100
float b=a/10
b should contain your answer
Some more code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
while (true)
{
string s;
s = Console.ReadLine();
int a = Convert.ToInt32(s);
a = a / 100;
float b = a / (float)10.0;
Console.WriteLine(b);
}
}
}
}
You should use modular (remainder) mathematics to do this. You don't need to involve the FPU (Floating Point Unit).
static string RoundAndToString(int value, int denominator)
{
var remainder = value % denominator;
value = (value - remainder) / denominator;
if (remainder == 0)
return value.ToString();
remainder = (remainder * 10) / denominator;
return string.Format("{0}{1}{2}", value, CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator, remainder);
}
Since you just want to truncate the number, it makes sense to convert it to a string, remove the last two characters from the string, then divide by 10 to get the corresponding number.
Here is the algorithm in Ruby. (I don't have C# handy)
a = 1000 #sample number
-> 1000
b = a.to_s[0..-3] #a converted to a string, then taking all characters except the last two.
-> "10"
c = b.to_i / 10.0 # converts to float in correct power
-> 1.0
You then display "c" in whatever format you want using sprintf (or the C# equivalent using FormatNumber).
try
int MyNumber = 10100;
string MyString = ((int) MyNumber/1000).ToString() + (( MyNumber % 1000) > 99 ? "." + (((int)( MyNumber / 100 )) % 10).ToString() : "");