Related
I have an entry field for Xamarin forms. Where I have to store the value in a decimal field.
And as per the requirement I have to have the data in ##.#### format.
The validation that it should be less than hundred I am doing it with success.
However I have an issue when truncating the problem.
My Unfocused even for the entry field is as follows.
private void RateEntry_UnFocused(object sender, FocusEventArgs e)
{
if (string.IsNullOrEmpty(((Entry)sender).Text))
{
((Entry)sender).Text = "0.00%";
_ProfileViewModel.Profile.Rate = (decimal)0.00;
}
else
{
_ProfileViewModel.Profile.Rate = Math.Truncate(Convert.ToDecimal(((Entry)sender).Text)* 10000)/10000;
((Entry)sender).Text = AddPercentageSymbol(_ProfileViewModel.Profile.Rate);
}
Validate();
}
for example if I give value as 99.9999 , I get the value as 99.99990000000000000%
Could you please help me to solve this issue.
Edit: Function AddPercentageSymbol
private string AddPercentageSymbol(decimal value)
{
return string.Format("{0}{1}", value, "%");
}
Edit: Expected Outputs
99.9999 = 99.9999%
99.9999766 = 99.9999%
99.99 = 99.99% or 99.9900%
0.76433 = 0.7643%
I've reproduced this - it looks like it's simply a bug in Mono. It's very easily demonstrated:
decimal x = 9m;
decimal y = x / 10;
Console.WriteLine(y);
This should be "0.9", but it's actually "0.9000000000000000000000000000".
Please report a bug in Mono :)
The good news is that you can use Math.Round to get rid of excess digits, e.g.
decimal z = Math.Round(y, 2);
Console.WriteLine(z); // 0.90
Assuming you were multiplying by 10000, truncating, and then dividing by 10000 to round (down) to 4 digits, you should be able to get away with using Math.Round(value, 4) as by then the value won't have any significant digits after 4 decimal places anyway.
I'm struggling to find a better way to preserve the 2 digit precision for decimal variable.
Here I have divided the question in 2 steps:
Step1: SQL Query
Inorder to get a 2 digit precision in a SQL query, I'm using
CONVERT(DECIMAL(10,2), .....) // to get 2 digit precision
On execution, I'm able to achieve the 2 digit precision in my SSMS.
NET_TOTAL
---------
10.00
12.50
14.25
Step2: via C# code
Whereas in my C# code, when I tried to store the value in my C# code it is not preserving the 2 digit precision.
NET_TOTAL
---------
10 //lost my precision
12.5 //lost my precision
14.25
Following is my variable declaration.
public decimal? NET_TOTAL { get; set; }
But I can smell a workaround using properties, but I'm not able to get it.
I'm using
dapper.net for database operations.
FileHelper.dll for converting the query list to a CSV file.
I would like to know the reason and a way to solve this problem.
Any help is much appreciated.
Thanks in advance.
Trailing zeros to the right of the decimal is not precision.
It is just presentation.
decimal d;
d = 10;
System.Diagnostics.Debug.WriteLine(string.Format("{0:N2}",d));
You can use
decimal.Round(value,decimalPoints);
This will return a decimal rounded upto decimalPoints.
You are confusing precision with representation. What you see in SSMS is a formatted number (a string). What you have in C# (and inside the DB) is a "true" number. In a true normally ending 0 after the decimal point aren't included.
If you want to format it you can do something like NET_TOTAL.ToString("0.00")
Note that there could be another problem:
NET_TOTAL = 1.245;
decimal sum = NET_TOTAL + NET_TOTAL;
the sum will be 2.29, but after a roundtrip to the DB NET_TOTAL will be 1.24 or 1.25 (depending on how the DB rounded 1.245) and the recalculated sum will be 2.28 or 2.3 .
is this acceptable:
private decimal? _netTotal;
public decimal? NET_TOTAL{
get{
return _netTotal;
}
set
{
if (value.HasValue)
{
_netTotal = Math.Truncate(value.Value, 2); // or rounding
}else{
_netTotal = value;
}
}
}
if you want to keep the original value but present it with 2 decimal places, then you could modify the getter instead: return Math.Truncate(value.Value, 2);
I'm trying to truncate a decimal part.
I mean create a function which do this.
1/9 ~ 0.11111111111111
So, if in the function set that wants to pick 5 decimals, must returns 0.11111
I was doing this using strings, but I guess is not a good idea. Is possible do that using math operations?
You can use
Math.Truncate
http://msdn.microsoft.com/en-us/library/7d101hyf.aspx
Edit: My version of a suitable method (though Gary has already shared one below)
public static double Truncate(double number, int digits)
{
double conversionFactor = (Math.Pow(10.0, digits));
return Math.Truncate(number * conversionFactor) / conversionFactor;
}
To truncate the decimal part of a given value by nDecimals, just use:
value = Math.Truncate(value * Math.Pow(10, nDecimals)) / Math.Pow(10, nDecimals);
so if value = 1/9 and nDecimals = 5, it returns 0.11111
Since Math.Truncate() does not allow to specify the number of digits you want to keep, you would have to multiply with 10^d first, truncate and divide by 10^d again, where d is the number of decimal digits you want to keep.
You can use a method like...
private double TruncateAt(double number, double decimals)
{
double factor = Math.Pow(10, decimals);
return Math.Truncate(number*factor)/factor;
}
And call the method by
double x = TruncateAt(1.0 / 9.0, 5);
If your program uses the same factor consistently, you may with to make it a const and get the performance improvement...
I'm not sure, especially since I haven't touched C# for awhile, but I think you could use Math.Round? Kinda like the way it is used here.
So, maybe try Math.Round(0.111111111, 6);?
I have a table with money field in my database. I have created entity and created decimal property for that money field. When the value of that field is displayed on My MVC3 view, It has four zeros 0000 after decimal like this : 5489.0000. I want to show only two 00 or decimal places. How can I fix it. Why it is showing four decimal places even I declared property as decimal.
Please suggest.
The SQL Server money datatype internally is a 64-bit integer with an implied scale of 4 decimal places. To quote Books Online, it is accurate "to ten-thousandsth of a currency unit." It is, the rough equivalent of a decimal(19,4).
The reason for the scale of 4 rather than 2 is to maintain precision in the results of arithmetic. Your ordinary currency value has a scale of 2 (e.g. $3.27) Multiplication or division of two numbers scaled to 2 decimal places gives a results that is precise to 4 decimal places: 9.23 divided by 3.27 yields a result of 2.82262996941896 (approximately). You can carry the result to whatever accuracy (number of decimal places) you desire. However, the result is only precise to 4 decimal places (2.8226) as the original values were only precise to 2 decimal places. That measurement is precise to within 1/2 of the smallest unit specified (+/- 0.005).
But I digress.
As a result of a SQL Server money value having an implied scale of 4, ADO.Net converts the value to a System.Decimal with a scale of 4. And since System.Decimal tracks scale, when you convert it to string, you get 4 decimal places.
To get fewer, you can
Round it before conversion, using the appropriate Decimal.Round() overload, or
Format it as desired (eg. (3.27M).ToString("0.00") ;.
Hope this helps.
This program:
namespace Sandbox
{
using System ;
class Program
{
static void Main( string[] args )
{
decimal pi = (decimal) Math.PI ;
string piText = pi.ToString("0.00");
Console.WriteLine("PI to 2 decimal places is {0} one way, and {1:0.00} another" , piText , pi ) ;
return;
}
}
}
Produces what you'd expect:
PI to 2 decimal places is 3.14 one way, and 3.14 another
Cheers,
N.
You have to format the string.
One thing you can do if it money you want to display is:
static void Main ()
{
decimal x = 0.999m;
decimal y = 9999999999999999999999999999m;
Console.WriteLine("My amount = {0:C}", x);
Console.WriteLine("Your amount = {0:C}", y);
}
}
OUTPUT:
Output
My amount = $1.00
Your amount = $9,999,999,999,999,999,999,999,999,999.00
the {0:C} is the currency Format
Hope this helps!
Here is everything you need to know about formatting strings.
http://blog.stevex.net/string-formatting-in-csharp/
I used this and it worked:
YourDecField.ToString("N")
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