How to check input double value contain how many digits? - c#

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 )

Related

Get Integer and Fractional part of a decimal number

Given X.Y, I want to get X and Y.
For instance, given 123.456 I want to get 123 and 456 (NOT 0.456).
I can do the following:
decimal num = 123.456M;
decimal integer = Math.Truncate(num);
decimal fractional = num - Math.Truncate(num);
// integer = 123
// fractional = 0.456 but I want 456
REF
As above-mentioned, using this method I will get 0.456, while I need 456. Sure I can do the following:
int fractionalNums = (int)((num - Math.Truncate(num)) * 1000);
// fracionalNums = 456
Additionally, this method requires knowing how many fractional numbers a given decimal number has so that you can multiply to that number (e.g., 123.456 has three, 123.4567 has four, 123.456789 has six, 123.1234567890123456789 has nineteen).
Few points to consider:
This operation will be executed millions of times; hence, performance is critical (maybe a bit-wise-based solution would do better);
Precision is critical, and no rounding is acceptable.
NOTE 1
For performance reasons, I am NOT interested in string manipulation-based approaches.
NOTE 2
The numbers in my question are of decimal type, hence methods that work for only decimal types and fail on float or double (due to floating point precision) are acceptable.
NOTE 3
Two sides of decimal (i.e., integer and fractional parts) can be considered two integers. Hence, 123.000456 is not an expected input; and even if it is given, it is acceptable to split it to 123 and 456 (because both sides are to be considered integers).
BitConverter.GetBytes(decimal.GetBits(num)[3])[2]; - number of digits after comma
long[] tens = new long[] {1, 10, 100, 1000, ...};
decimal num = 123.456M;
int iPart = (int)num;
decimal dPart = num - iPart;
int count = BitConverter.GetBytes(decimal.GetBits(num)[3])[2];
long pow = tens[count];
Console.WriteLine(iPart);
Console.WriteLine((long)(dPart * pow));
Decimal has a 96 bit mantissa, so a long is not good enough to get every possible value.
Define all (positive) powers of 10 defined for Decimal:
decimal mults[] = {1M, 1e1M, 1e2M, 1e3M, <insert rest here>, 1e27M, 1e28M};
Then, inside the loop you need to get the scale (the power of 10 by which the "mantissa" is divided to get the nominal value of the decimal):
int[] bits = Decimal.GetBits(n);
int scale = (bits[3] >> 16) & 31; // 567.1234 represented as 5671234 x 10^-4
decimal intPart = (int)n; // 567.1234 --> 567
decimal decPart = (n - intPart) * mults[scale]; // 567.1234 --> 0.1234 --> 1234
The easiest way is probably to convert the number to string.
Then take the substring after the decimal point, and convert it back to int.

Is there any drawback if i convert a string to Double then compare the result to integer value (such as 2000, 1000)

I am not sure if i am doing things correctly inside my asp.net application. now i have 3 fields which represents currency fields, which allow maximum of 2 decimals:-
OneTimeCost
MonthlyCost
AnnualCost
and i am calculating this value:-
var totalcost = double.Parse(currentItem["OnTimeCost"].ToString()) + (double.Parse(currentItem["MonthlyCost"].ToString()) * 12) + double.Parse(currentItem["AnnualCost"].ToString());
then i am comparing the result as follow:-
if( totalcost >= 2000)
{
}
else if (totalcost > 1000)
{
}
//and so on
Now i am not sure if i am doing things correctly or not? now the 3 fields i have, represents currency values which can allow 2 decimal points. so not sure if converting my values to double and then compare the result to integer values (2000 and 1000) is a correct and safe operation?
second question. is it better to use decimal.parse instead of double.parse? since decimal is more appropriate for financial calculations ?
so not sure if converting my values to double and then compare the
result to integer values (2000 and 1000) is a correct and safe
operation?
Yes, it's safe.
second question. is it better to use decimal.parse instead of
double.parse? since decimal is more appropriate for financial
calculations ?
if you're dealing with money then use decimal as that's why it's there.

Compare decimals to 1 decimal point?

I'm new to C# (Come from Java/C++ at uni so it's not really that new I guess) but for a project I'm needing to compare decimals.
e.g.
a = 1234.123
b = 1234.142
Decimal.Compare() will of course say they're not the same as a is smaller than b. What I want to do is compare it to that first decimal place (1 and 1) so it would return true.
The only way I've been able to think of is to convert it to use Decimal.GetBits() but I was hoping there is a simpler way I just haven't thought of yet.
You can round a decimal to one fractional digit and then compare them.
if (Decimal.Round(d1,1) == Decimal.Round(d2,1))
Console.WriteLine("Close enough.");
And, if rounding (with default midpoint handling) is not what you want, Decimal types can also be used with all the other options, like those I covered in this earlier answer.
You can use Math.Truncate(Decimal) (MSDN)
Calculates the integral part of a specified decimal number.
Coding example.
Decimal a = 1234.123m;
Decimal b = 1234.142m;
Decimal A = Math.Truncate(a * 10);
Console.WriteLine(A);// <= Will out 12341
Decimal B = Math.Truncate(b * 10);
Console.WriteLine(B);// <= Will out 12341
Console.WriteLine(Decimal.Compare(A, B)); // Will out 0 ; A and B are equal. Which means a,b are equal to first decimal place
Note : This was tested and posted .
Also simple one line comparison :
Decimal a = 1234.123m;
Decimal b = 1234.142m;
if(Decimal.Compare(Math.Truncate(a*10),Math.Truncate(b*10))==0){
Console.WriteLine("Equal upto first decimal place"); // <= Will out this for a,b
}

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

Categories

Resources