I have a simple example application here where I am multiplying and adding double variables and then comparing them against an expected result. In both cases the result is equal to the expected result yet when I do the comparison it fails.
static void Main(string[] args)
{
double a = 98.1;
double b = 107.7;
double c = 92.5;
double d = 96.5;
double expectedResult = 88.5;
double result1 = (1*2*a) + (-1*1*b);
double result2 = (1*2*c) + (-1*1*d);
Console.WriteLine(String.Format("2x{0} - {1} = {2}\nEqual to 88.5? {3}\n", a, b, result1, expectedResult == result1));
Console.WriteLine(String.Format("2x{0} - {1} = {2}\nEqual to 88.5? {3}\n", c, d, result2, expectedResult == result2));
Console.Read();
}
And here is the output:
2x98.1 - 107.7 = 88.5
Equal to 88.5? False
2x92.5 - 96.5 = 88.5
Equal to 88.5? True
I need to be able to capture that it is in fact True in BOTH cases. How would I do it?
Floating point numbers often don't contain the exact value that mathematics tells us, because of how they store numbers.
To still have a reliable comparison, you need to allow some difference:
private const double DoubleEpsilon = 2.22044604925031E-16;
/// <summary>Determines whether <paramref name="value1"/> is very close to <paramref name="value2"/>.</summary>
/// <param name="value1">The value1.</param>
/// <param name="value2">The value2.</param>
/// <returns><c>true</c> if <paramref name="value1"/> is very close to value2; otherwise, <c>false</c>.</returns>
public static bool IsVeryCloseTo(this double value1, double value2)
{
if (value1 == value2)
return true;
var tolerance = (Math.Abs(value1) + Math.Abs(value2)) * DoubleEpsilon;
var difference = value1 - value2;
return -tolerance < difference && tolerance > difference;
}
Please also make sure to read this blog post.
If you need more precision (for money and such) then use decimal.
var a = 98.1M;
var b = 107.7M;
var c = 92.5M;
var d = 96.5M;
var expectedResult = 88.5M;
var result1 = (2 * a) + (-1 * b);
var result2 = (2 * c) + (-1 * d);
Console.WriteLine(String.Format("2x{0} - {1} = {2}\nEqual to 88.5? {3}\n", a, b, result1, expectedResult == result1));
Console.WriteLine(String.Format("2x{0} - {1} = {2}\nEqual to 88.5? {3}\n", c, d, result2, expectedResult == result2));
Output:
2x98.1 - 107.7 = 88.5
Equal to 88.5? True
2x92.5 - 96.5 = 88.5
Equal to 88.5? True
It's a problem with how floating point numbers are represented in memory.
You should read this to get a better understanding of whats going on: What Every Computer Scientist Should Know About Floating-Point Arithmetic
Simply change your rounding to level 2 , this will give TRUE
double result1 =Math.Round ( (1 * 2 * a) + (-1 * 1 * b),2);
using Math.Round() will round result1 to the correct decimal
result1 = Math.Round(result1, 1);
using the debugger,
result1=88.499999999999986;
expectedResult = 88.5
So when using the double ,these are not equal.
There is a whole school of thought that is against using Double.Epsilon and similar numbers...
I think they use this: (taken from https://stackoverflow.com/a/2411661/613130 but modified with the checks for IsNaN and IsInfinity suggested here by nobugz
public static bool AboutEqual(double x, double y)
{
if (double.IsNaN(x)) return double.IsNaN(y);
if (double.IsInfinity(x)) return double.IsInfinity(y) && Math.Sign(x) == Math.Sign(y);
double epsilon = Math.Max(Math.Abs(x), Math.Abs(y)) * 1E-15;
return Math.Abs(x - y) <= epsilon;
}
The 1E-15 "magic number" is based on the fact that doubles have a little more than 15 digits of precision.
I'll add that for your numbers it returns true :-)
Related
I have some problems with my code where I think the accuracy is a bit off. I'll take out the declarations of variables from my code, so the code is as small as possible:
int a = Int32.Parse(tb_weight.Text);
double b = 0;
b = (a * 1.03) / 1000;
double g = 0;
g = (1.09 + (0.41 * (Math.Sqrt(50 / b))));
lbl_vertforce.Content = Math.Round((b * g * 9.81), 2);
So, tb_weight is a textbox where the input is made, and lets say the input is 5000, the label lbl_vertforce is showing 119,61 and according to my calculator, it should show 119,74. What is wroing here?
Doubles are not 100% precise and can vary in the least common digits. If you want exact precision you need to use Decimal type which has a bigger memory foot print, but was designed to be very precise. Unfortunately Math.Sqrt is not overloaded for Decimal and only works on doubles. I have provide code I found in another posting discussing the subject of Decimal Square roots: Performing Math operations on decimal datatype in C#?
public void YourCodeModifiedForDecimal()
{
int a = Int32.Parse(tb_weight.Text);
decimal b = 0;
b = (a* 1.03m) / 1000m;
decimal g = 0;
g = (1.09m + (0.41m * (Sqrt(50m / b))));
lbl_vertforce.Content = Math.Round((b* g * 9.81m), 2);
}
public static decimal Sqrt(decimal x, decimal? guess = null)
{
var ourGuess = guess.GetValueOrDefault(x / 2m);
var result = x / ourGuess;
var average = (ourGuess + result) / 2m;
if (average == ourGuess) // This checks for the maximum precision possible with a decimal.
return average;
else
return Sqrt(x, average);
}
You need to round g to 2 decimal places to get 119.74 in the final calculation.
g = Math.Round(1.09 + (0.41 * (Math.Sqrt(50 / b))), 2);
I just wrote my first C# program.
It's a simple piece of code which solves quadratic equations.
It works with some functions (such as -6x2-6x+12) perfectly, while with others, (4x2-20x+25) it exhibits what I suspect are rounding errors.
I'm completely new to C#, and I can't see an problems; would someone be able to help me debug this code?
namespace ConsoleApplication {
class Program {
static int ObtainInput(string prompt, bool canBeZero) {
double a = ObtainInput("A? ", false);
double b = ObtainInput("B? ", true);
double c = ObtainInput("C? ", true);
double d, x1, x2;
while (true) {
Console.Write(prompt);
string input = Console.ReadLine();
int result;
bool success = int.TryParse(input, out result);
if (success && (canBeZero || result != 0))
return result;
Console.WriteLine("Invalid input!");
}
// Calculating a discriminant
d = b * b - 4 * a * c;
if (d == 0) {
x1 = -b / (2 * a);
Console.WriteLine("The only solution is x={0}.", x1);
Console.ReadLine();
}
// If d < 0, no real solutions exist
else if (d < 0) {
Console.WriteLine("There are no real solutions");
Console.ReadLine();
}
// If d > 0, there are two real solutions
else {
x1 = (-b - Math.Sqrt(d)) / (2 * a);
x2 = (-b + Math.Sqrt(d)) / (2 * a);
Console.WriteLine("x1={0} and x2={1}.", x1, x2);
Console.ReadLine();
}
}
}
}
I just wrote my first C# program.
Awesome. Now would be a great time to not get into bad habits:
entA: Console.Write("a?");
try { a = Convert.ToInt32(Console.ReadLine()); }
catch
{ /*If a=0, the equation isn't quadratic*/
Console.WriteLine("Invalid input");
goto entA;
}
Problems abound. First off, use int.TryParse, rather than putting a try-catch around something that can fail.
Second, the comment does not match the action of the code. The code determines if the result is an integer; the comment says that it checks for zero.
Third, do not use a goto when what you are attempting to represent is a loop.
Fourth, look at all that duplicated code! You have the same code repeated three times with minor variations.
Make yourself a helper method:
static int ObtainInput(string prompt, bool canBeZero)
{
while(true) // loop forever!
{
Console.Write(prompt);
string input = Console.ReadLine();
int result;
bool success = int.TryParse(input, out result);
if (success && (canBeZero || result != 0))
return result;
Console.WriteLine("Invalid input!");
}
}
And now your mainline is:
int a = ObtainInput("A? ", false);
int b = ObtainInput("B? ", true);
int c = ObtainInput("C? ", true);
Your bug though is here:
x1 = x2 = -b / (2 * a);
You do the arithmetic in integers, and then convert to doubles. That is, you do the division, round to the nearest integer, and then convert to double. Do it in doubles (or, less likely, in decimals) from the start. It should be:
double a = ObtainInput("A? ", false);
double b = ObtainInput("B? ", true);
double c = ObtainInput("C? ", true);
That is, a, b, and c should not ever be integers.
You're doing integer division when assigning to x1 and x2; (you can just change the 2 to 2.0 to change it to double division and get a double result)
It might also make sense to change your a,b,c, and d values to double which will also get past the problem, and allow people to enter non-int values for the coefficients.
int a, b, c;
int d;
first of all, try to use double instead of int, since 1/3 = 0 using integers.
In my C# program I have a double obtained from some computation and its value is something like 0,13999 or 0,0079996 but this value has to be presented to a human so it's better displayed as 0,14 or 0,008 respectively.
So I need to round the value, but have no idea to which precision - I just need to "throw away those noise digits".
How could I do that in my code?
To clarify - I need to round the double values to a precision that is unknown at compile time - this needs to be determined at runtime. What would be a good heuristic to achieve this?
You seem to want to output a value which is not very different to the input value, so try increasing numbers of digits until a given error is achieved:
static double Round(double input, double errorDesired)
{
if (input == 0.0)
return 0.0;
for (int decimals = 0; decimals < 17; ++decimals)
{
var output = Math.Round(input, decimals);
var errorAchieved = Math.Abs((output - input) / input);
if (errorAchieved <= errorDesired)
return output;
}
return input;
}
}
static void Main(string[] args)
{
foreach (var input in new[] { 0.13999, 0.0079996, 0.12345 })
{
Console.WriteLine("{0} -> {1} (.1%)", input, Round(input, 0.001));
Console.WriteLine("{0} -> {1} (1%)", input, Round(input, 0.01));
Console.WriteLine("{0} -> {1} (10%)", input, Round(input, 0.1));
}
}
private double PrettyRound(double inp)
{
string d = inp.ToString();
d = d.Remove(0,d.IndexOf(',') + 1);
int decRound = 1;
bool onStartZeroes = true;
for (int c = 1; c < d.Length; c++ )
{
if (!onStartZeroes && d[c] == d[c - 1])
break;
else
decRound++;
if (d[c] != '0')
onStartZeroes = false;
}
inp = Math.Round(inp, decRound);
return inp;
}
Test:
double d1 = 0.13999; //no zeroes
double d2 = 0.0079996; //zeroes
double d3 = 0.00700956; //zeroes within decimal
Response.Write(d1 + "<br/>" + d2 + "<br/>" + d3 + "<br/><br/>");
d1 = PrettyRound(d1);
d2 = PrettyRound(d2);
d3 = PrettyRound(d3);
Response.Write(d1 + "<br/>" + d2 + "<br/>" + d3 +"<br/><br/>");
Prints:
0,13999
0,0079996
0,00700956
0,14
0,008
0,007
Rounds your numbers as you wrote in your example..
I can think of a solution though it isn't very efficient...
My assumption is that you can tell when a number is in the "best" human readable format when extra digits make no difference to how it is rounded.
eg in the example of 0,13999 rounding it to various numbers of decimal places gives:
0
0.1
0.14
0.14
0.14
0.13999
I'd suggest that you could loop through and detect that stable patch and cut off there.
This method seems to do this:
public double CustomRound(double d)
{
double currentRound = 0;
int stability = 0;
int roundLevel = 0;
while (stability < 3)
{
roundLevel++;
double current = Math.Round(d, roundLevel);
if (current == currentRound)
{
stability++;
}
else
{
stability = 1;
currentRound=current;
}
}
return Math.Round(d, roundLevel);
}
This code might be cleanable but it does the job and is a sufficient proof of concept. :)
I should emphasise that that initial assumption (that no change when rounding) is the criteria we are looking at which means that something like 0.3333333333 will not get rounded at all. With the examples given I'm unable to say if this is correct or not but I assume if this is a double issues that the problem is with the very slight variations from the "right" value and the value as a double.
Heres what I tried:
public decimal myRounding(decimal number)
{
double log10 = Math.Log10((double) number);
int precision = (int)(log10 >= 0 ? 0 : Math.Abs(log10)) + (number < 0.01m ? 1 : 2);
return Math.Round(number, precision);
}
test:
Console.WriteLine(myRounding(0.0000019999m)); //0.000002
Console.WriteLine(myRounding(0.0003019999m)); //0.0003
Console.WriteLine(myRounding(2.56777777m)); //2.57
Console.WriteLine(myRounding(0.13999m)); //0.14
Console.WriteLine(myRounding(0.0079996m)); //0.008
You can do it without converting to string. This is what I created fast:
private static double RoundDecimal(double number)
{
double temp2 = number;
int temp, counter = 0;
do
{
temp2 = 10 * temp2;
temp = (int)temp2;
counter++;
} while (temp < 1);
return Math.Round(number, counter < 2 ? 2 : counter);
}
or
private static double RoundDecimal(double number)
{
int counter = 0;
if (number > 0) {
counter = Math.Abs((int) Math.Log10(number)) + 1;
return Math.Round(arv, counter < 2 ? 2 : counter);
}
After giving it another thought I did the following and looks like it does what I want so far.
I iterate over the number of digits and compare Round( value, number ) and Round( value, number + 1 ). Once they are equal (not == of course - I compare the difference against a small number) then number is the number of digits I'm looking for.
Double.ToString() can take a string format as an argument. This will display as many characters as you require, rounding to the decimal place. E.G:
double Value = 1054.32179;
MessageBox.Show(Value.ToString("0.000"));
Will display "1054.322".
Source
Generic formats (i.e, pre-generated)
How to generate custom formats
You can use no of digits with Math.Round Function
Double doubleValue = 4.052102;
Math.Round(doubleValue, 2);
This will return 4.05 as your required answer.
This is tested code, can u explain me how i am wrong. So i need to change.
I need to split an double value, into two int value, one before the decimal point and one after. The int after the decimal point should have two digits.
Example:
10.50 = 10 and 50
10.45 = 10 and 45
10.5 = 10 and 50
This is how you could do it:
string s = inputValue.ToString("0.00", CultureInfo.InvariantCulture);
string[] parts = s.Split('.');
int i1 = int.Parse(parts[0]);
int i2 = int.Parse(parts[1]);
Manipulating strings can be slow. Try using the following:
double number;
long intPart = (long) number;
double fractionalPart = number - intPart;
What programming language you want to use to do this? Most of the language should have a Modulo operator. C++ example:
double num = 10.5;
int remainder = num % 1
"10.50".Split('.').Select(int.Parse);
/// <summary>
/// Get the integral and floating point portions of a Double
/// as separate integer values, where the floating point value is
/// raised to the specified power of ten, given by 'places'.
/// </summary>
public static void Split(Double value, Int32 places, out Int32 left, out Int32 right)
{
left = (Int32)Math.Truncate(value);
right = (Int32)((value - left) * Math.Pow(10, places));
}
public static void Split(Double value, out Int32 left, out Int32 right)
{
Split(value, 1, out left, out right);
}
Usage:
Int32 left, right;
Split(10.50, out left, out right);
// left == 10
// right == 5
Split(10.50, 2, out left, out right);
// left == 10
// right == 50
Split(10.50, 5, out left, out right);
// left == 10
// right == 50000
how about?
var n = 1004.522
var a = Math.Floor(n);
var b = n - a;
Another variation that doesn't involve string manipulation:
static void Main(string[] args)
{
decimal number = 10123.51m;
int whole = (int)number;
decimal precision = (number - whole) * 100;
Console.WriteLine(number);
Console.WriteLine(whole);
Console.WriteLine("{0} and {1}",whole,(int) precision);
Console.Read();
}
Make sure they're decimals or you get the usual strange float/double behaviour.
you can split with string and then convert into int ...
string s = input.ToString();
string[] parts = s.Split('.');
This function will take time in decimal and converts back into base 60 .
public string Time_In_Absolute(double time)
{
time = Math.Round(time, 2);
string[] timeparts = time.ToString().Split('.');
timeparts[1] = "." + timeparts[1];
double Minutes = double.Parse(timeparts[1]);
Minutes = Math.Round(Minutes, 2);
Minutes = Minutes * (double)60;
return string.Format("{0:00}:{1:00}",timeparts[0],Minutes);
//return Hours.ToString() + ":" + Math.Round(Minutes,0).ToString();
}
Try:
string s = "10.5";
string[] s1 = s.Split(new char[] { "." });
string first = s1[0];
string second = s1[1];
You can do it without going through strings. Example:
foreach (double x in new double[]{10.45, 10.50, 10.999, -10.323, -10.326, 10}){
int i = (int)Math.Truncate(x);
int f = (int)Math.Round(100*Math.Abs(x-i));
if (f==100){ f=0; i+=(x<0)?-1:1; }
Console.WriteLine("("+i+", "+f+")");
}
Output:
(10, 45)
(10, 50)
(11, 0)
(-10, 32)
(-10, 33)
(10, 0)
Won't work for a number like -0.123, though. Then again, I'm not sure how it would fit your representation.
I actually just had to answer this in the real world and while #David Samuel's answer did part of it here is the resulting code I used. As said before Strings are way too much overhead. I had to do this calculation across pixel values in a video and was still able to maintain 30fps on a moderate computer.
double number = 4140 / 640; //result is 6.46875 for example
int intPart = (int)number; //just convert to int, loose the dec.
int fractionalPart = (int)((position - intPart) * 1000); //rounding was not needed.
//this procedure will create two variables used to extract [iii*].[iii]* from iii*.iii*
This was used to solve x,y from pixel count in 640 X 480 video feed.
Console.Write("Enter the amount of money: ");
double value = double.Parse(Console.ReadLine());
int wholeDigits = (int) value;
double fractionalDigits = (value - wholeDigits) * 100;
fractionalDigits = (int) fractionalDigits;
Console.WriteLine(
"The number of the shekels is {0}, and the number of the agurot is {1}",
wholeDigits, fractionalDigits);
Using Linq. Just clarification of #Denis answer.
var parts = "10.50".Split('.').Select(int.Parse);
int i1 = parts.ElementAt(0);
int i2 = parts.ElementAt(1);
How do I tell if a decimal or double value is an integer?
For example:
decimal d = 5.0; // Would be true
decimal f = 5.5; // Would be false
or
double d = 5.0; // Would be true
double f = 5.5; // Would be false
The reason I would like to know this is so that I can determine programmatically if I want to output the value using .ToString("N0") or .ToString("N2"). If there is no decimal point value, then I don't want to show that.
For floating point numbers, n % 1 == 0 is typically the way to check if there is anything past the decimal point.
public static void Main (string[] args)
{
decimal d = 3.1M;
Console.WriteLine((d % 1) == 0);
d = 3.0M;
Console.WriteLine((d % 1) == 0);
}
Output:
False
True
Update: As #Adrian Lopez mentioned below, comparison with a small value epsilon will discard floating-point computation mis-calculations. Since the question is about double values, below will be a more floating-point calculation proof answer:
Math.Abs(d % 1) <= (Double.Epsilon * 100)
There are any number of ways to do this. For example:
double d = 5.0;
bool isInt = d == (int)d;
You can also use modulo.
double d = 5.0;
bool isInt = d % 1 == 0;
How about this?
public static bool IsInteger(double number) {
return number == Math.Truncate(number);
}
Same code for decimal.
Mark Byers made a good point, actually: this may not be what you really want. If what you really care about is whether a number rounded to the nearest two decimal places is an integer, you could do this instead:
public static bool IsNearlyInteger(double number) {
return Math.Round(number, 2) == Math.Round(number);
}
Whilst the solutions proposed appear to work for simple examples, doing this in general is a bad idea. A number might not be exactly an integer but when you try to format it, it's close enough to an integer that you get 1.000000. This can happen if you do a calculation that in theory should give exactly 1, but in practice gives a number very close to but not exactly equal to one due to rounding errors.
Instead, format it first and if your string ends in a period followed by zeros then strip them. There are also some formats that you can use that strip trailing zeros automatically. This might be good enough for your purpose.
double d = 1.0002;
Console.WriteLine(d.ToString("0.##"));
d = 1.02;
Console.WriteLine(d.ToString("0.##"));
Output:
1
1.02
bool IsInteger(double num) {
if (ceil(num) == num && floor(num) == num)
return true;
else
return false;
}
Problemo solvo.
Edit: Pwned by Mark Rushakoff.
static bool IsWholeNumber(double x)
{
return Math.Abs(x % 1) < double.Epsilon;
}
Mark Rushakoff's answer may be simpler, but the following also work and may be more efficient since there is no implicit division operation:
bool isInteger = (double)((int)f) == f ;
and
bool isInteger = (decimal)((int)d) == d ;
If you want a single expression for both types, perhaps
bool isInteger = (double)((int)val) == (double)val ;
.NET 7 now has built-in methods for this:
decimal.IsInteger: https://learn.microsoft.com/en-us/dotnet/api/system.decimal.isinteger?view=net-7.0
double.IsInteger: https://learn.microsoft.com/en-us/dotnet/api/system.double.isinteger?view=net-7.0
You can check out the source code at:
https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Decimal.cs
https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Double.cs
If upper and lower bound of Int32 matters:
public bool IsInt32(double value)
{
return value >= int.MinValue && value <= int.MaxValue && value == (int)value;
}
You can use String formatting for the double type. Here is an example:
double val = 58.6547;
String.Format("{0:0.##}", val);
//Output: "58.65"
double val = 58.6;
String.Format("{0:0.##}", val);
//Output: "58.6"
double val = 58.0;
String.Format("{0:0.##}", val);
//Output: "58"
Let me know if this doesn't help.
public static bool isInteger(decimal n)
{
return n - (Int64)n == 0;
}
I faced a similar situation, but where the value is a string. The user types in a value that's supposed to be a dollar amount, so I want to validate that it's numeric and has at most two decimal places.
Here's my code to return true if the string "s" represents a numeric with at most two decimal places, and false otherwise. It avoids any problems that would result from the imprecision of floating-point values.
try
{
// must be numeric value
double d = double.Parse(s);
// max of two decimal places
if (s.IndexOf(".") >= 0)
{
if (s.Length > s.IndexOf(".") + 3)
return false;
}
return true;
catch
{
return false;
}
I discuss this in more detail at http://progblog10.blogspot.com/2011/04/determining-whether-numeric-value-has.html.
Using int.TryParse will yield these results:
var shouldBeInt = 3;
var shouldntBeInt = 3.1415;
var iDontWantThisToBeInt = 3.000f;
Console.WriteLine(int.TryParse(shouldBeInt.ToString(), out int parser)); // true
Console.WriteLine(int.TryParse(shouldntBeInt.ToString(), out parser)); // false
Console.WriteLine(int.TryParse(iDontWantThisToBeInt.ToString(), out parser)); // true, even if I don't want this to be int
Console.WriteLine(int.TryParse("3.1415", out parser)); // false
Console.WriteLine(int.TryParse("3.0000", out parser)); // false
Console.WriteLine(int.TryParse("3", out parser)); // true
Console.ReadKey();
You can simply compare the double against the int cast of the same value.
double d = 5.0m;
if (d == (int)d)
{
....
}
This is my solution to this problem. Maybe someone will useful.
public static bool IsInt(object number, int? decimalPlaces = null)
{
bool isInt;
var splinted = number.ToString().Split(',');
if (splinted.Length == 1)
isInt = true;
else
{
var charsAfterComma = decimalPlaces != null ? splinted[1].Substring(0, (int) decimalPlaces) : splinted[1];
isInt = charsAfterComma.First().ToString() == "0" && charsAfterComma.Replace("0", "") == "";
}
return isInt;
}
Try this:
number == Convert.ToInt16(number);
Perhaps not the most elegant solution but it works if you are not too picky!
bool IsInteger(double num) {
return !num.ToString("0.################").Contains(".");
}