Decimal Truncating adding unlimited zeros - c#

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.

Related

Keep one number after decimal point, not rounding

I have a double variable in c#:
DoubleVar = 3.488;
I want to keep only one digit after decimal point, not rounding. For example:
3.4
Thanks so much in advance.
Since you specified "no rounding", and did not specify that this was being displayed as text. Then the following will Truncate to 1 decimal place
value = Math.Truncate(value * 10) / 10
Note: with floats you are likely going to get artefacts anyway, as there are numbers which can't be represented in base 2.
public static void Main()
{
double val = 1.33;
Console.WriteLine(String.Format("{0:0.#}", val));
}

Finding the number of places after the decimal point of a Double

I have a Double value:
double a = 4.5565;
What is the easiest way to calculate the number of digits after the decimal point (4 in this case).
I know that I can convert to string and do a split and take the length. But is there an easier way?
There's no easy way, especially since the number of digits mathematically speaking might be far more than displayed. For example, 4.5565 is actually stored as 4.556499999999999772626324556767940521240234375 (thanks to harold for calculating that). You're very unlikely to find a useful solution to this problem.
EDIT
You could come up with some algorithm that works like this: if, as you calculate the decimal representation, you find a certain number of 9s (or zeros) in succession, you round up (or down) to the last place before the series of 9s (or zeros) began. I suspect that you would find more trouble down that road than you would anticipate.
var precision = 0;
var x = 1.345678901m;
while (x*(decimal)Math.Pow(10,precision) !=
Math.Round(x*(decimal)Math.Pow(10,precision)))
precision++;
precision will be equal to the number of significant digits of the decimal value (setting x to 1.23456000 will result in a precision of 5 even though 8 digits were originally specified in the literal). This executes in time proportional to the number of decimal places. It counts the number of fractional digits ONLY; you can count the number of places to the left of the decimal point by taking the integer part of Math.Log10(x). It works best with decimals as they have better value precision so there is less rounding error.
Write a function
int CountDigitsAfterDecimal(double value)
{
bool start = false;
int count = 0;
foreach (var s in value.ToString())
{
if (s == '.')
{
start = true;
}
else if (start)
{
count++;
}
}
return count;
}
I think this might be a solution:
private static int getDecimalCount(double val)
{
int i=0;
while (Math.Round(val, i) != val)
i++;
return i;
}
double val9 = 4.5565d; int count9 = getDecimalCount(val9);//result: 4
Sorry for the duplication -> https://stackoverflow.com/a/35238462/1266873
base on james answer bat much clearer:
int num = dValue.ToString().Length - (((int)dValue).ToString().Length + 1);
num is the exact number of digits after the decimal point.
without including 0 like this(25.520000)
in this case, you will get num= 2
I Think String solution is best : ((a-(int)a)+"").length-2
I'll perhaps use this code if I needed,
myDoubleNumber.ToString("R").Split('.')[1].Length
"R" here is Round Trip Format Specifier
We need to check for the index bounds first of course.
Another solution would be to use some string functions:
private int GetSignificantDecimalPlaces(decimal number, bool trimTrailingZeros = true)
{
var stemp = Convert.ToString(number);
if (stemp.IndexOf(Application.CurrentCulture.NumberFormat.NumberDecimalSeparator) < 0)
return 0;
if (trimTrailingZeros)
stemp = stemp.TrimEnd('0');
return stemp.Length - 1 - stemp.IndexOf(Application.CurrentCulture.NumberFormat.NumberDecimalSeparator);
}
Remember to use System.Windows.Forms to get access to Application.CurrentCulture

Properly round financial data

I decided to re-create my question:
decimal dTotal = 0m;
foreach (DictionaryEntry item in _totals)
{
if (!string.IsNullOrEmpty(item.Value.ToString()))
{
dTotal += Convert.ToDecimal(item.Value);
}
}
Console.WriteLine(dTotal / 3600m);
Console.WriteLine(decimal.Round(dTotal / 3600m, 2));
Console.WriteLine(decimal.Divide(dTotal, 3600m));
The above code returns:
579.99722222222222222222222222
580.00
579.99722222222222222222222222
So, that is where my issues are coming from, I really need it to just display the 579.99; but any round, be it decimal.Round or Math.Round still return 580; even the string formats for {0:F} return 580.00.
How can i properly do this?
New answer (to new question)
Okay, so you've got a value of 579.99722222222222222222222222 - and you're asking that to be rounded to two decimal places. Isn't 580.00 the natural answer? It's closer to the original value than 579.99 is. It sounds like you essentially want flooring behaviour, but with a given number of digits. For that, you can use:
var floored = Math.Floor(original * 100) / 100;
In this case, you can do both in one step:
var hours = Math.Floor(dTotal / 36) / 100;
... which is equivalent to
var hours = Math.Floor((dTotal / 3600) * 100) / 100;
Original answer (to original question)
Sounds like you've probably got payTotal in an inappropriate form to start with:
using System;
class Test
{
static void Main()
{
decimal pay = 2087975.7m;
decimal time = pay / 3600;
Console.WriteLine(time); // Prints 579.99325
}
}
This is the problem:
var payTotal = 2087975.7;
That's assigning payTotal to a double variable. The value you've actually got is 2087975.69999999995343387126922607421875, which isn't what you wanted. Any time you find yourself casting from double to decimal or vice versa, you should be worried: chances are you've used the wrong type somewhere. Currency values should absolutely be stored in decimal rather than double (and there are various other Stack Overflow questions talking about when to use which).
See my two articles on floating point for more info:
Binary floating point in .NET
Decimal floating point in .NET
(Once you've got correct results, formatting them is a different matter of course, but that shouldn't be too bad...)

Truncate number of digit of double value in C#

How can i truncate the leading digit of double value in C#,I have tried Math.Round(doublevalue,2) but not giving the require result. and i didn't find any other method in Math class.
For example i have value 12.123456789 and i only need 12.12.
EDIT: It's been pointed out that these approaches round the value instead of truncating. It's hard to genuinely truncate a double value because it's not really in the right base... but truncating a decimal value is more feasible.
You should use an appropriate format string, either custom or standard, e.g.
string x = d.ToString("0.00");
or
string x = d.ToString("F2");
It's worth being aware that a double value itself doesn't "know" how many decimal places it has. It's only when you convert it to a string that it really makes sense to do so. Using Math.Round will get the closest double value to x.xx00000 (if you see what I mean) but it almost certainly won't be the exact value x.xx00000 due to the way binary floating point types work.
If you need this for anything other than string formatting, you should consider using decimal instead. What does the value actually represent?
I have articles on binary floating point and decimal floating point in .NET which you may find useful.
What have you tried? It works as expected for me:
double original = 12.123456789;
double truncated = Math.Truncate(original * 100) / 100;
Console.WriteLine(truncated); // displays 12.12
double original = 12.123456789;
double truncated = Truncate(original, 2);
Console.WriteLine(truncated.ToString());
// or
// Console.WriteLine(truncated.ToString("0.00"));
// or
// Console.WriteLine(Truncate(original, 2).ToString("0.00"));
public static double Truncate(double value, int precision)
{
return Math.Truncate(value * Math.Pow(10, precision)) / Math.Pow(10, precision);
}
How about:
double num = 12.12890;
double truncatedNum = ((int)(num * 100))/100.00;
This could work (although not tested):
public 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);
This code....
double x = 12.123456789;
Console.WriteLine(x);
x = Math.Round(x, 2);
Console.WriteLine(x);
Returns this....
12.123456789
12.12
What is your desired result that is different?
If you want to keep the value as a double, and just strip of any digits after the second decimal place and not actually round the number then you can simply subtract 0.005 from your number so that round will then work. For example.
double x = 98.7654321;
Console.WriteLine(x);
double y = Math.Round(x - 0.005, 2);
Console.WriteLine(y);
Produces this...
98.7654321
98.76
There are a lot of answers using Math.Truncate(double).
However, the approach using Math.Truncate(double) can lead to incorrect results.
For instance, it will return 5.01 truncating 5.02, because multiplying of double values doesn't work precisely and 5.02*100=501.99999999999994
If you really need this precision, consider, converting to Decimal before truncating.
public static double Truncate(double value, int precision)
{
decimal power = (decimal)Math.Pow(10, precision);
return (double)(Math.Truncate((decimal)value * power) / power);
}
Still, this approach is ~10 times slower.
I'm sure there's something more .netty out there but why not just:-
double truncVal = Math.Truncate(val * 100) / 100;
double remainder = val-truncVal;
If you are looking to have two points after the decimal without rounding the number, the following should work
string doubleString = doublevalue.ToString("0.0000"); //To ensure we have a sufficiently lengthed string to avoid index issues
Console.Writeline(doubleString
.Substring(0, (doubleString.IndexOf(".") +1) +2));
The second parameter of substring is the count, and IndexOf returns to zero-based index, so we have to add one to that before we add the 2 decimal values.
This answer is assuming that the value should NOT be rounded
For vb.net use this extension:
Imports System.Runtime.CompilerServices
Module DoubleExtensions
<Extension()>
Public Function Truncate(dValue As Double, digits As Integer)
Dim factor As Integer
factor = Math.Pow(10, digits)
Return Math.Truncate(dValue * factor) / factor
End Function
End Module
I use a little formatting class that I put together which can add gaps and all sorts.
Here is one of the methods that takes in a decimal and return different amounts of decimal places based on the decimal display setting in the app
public decimal DisplayDecimalFormatting(decimal input, bool valueIsWeightElseMoney)
{
string inputString = input.ToString();
if (valueIsWeightElseMoney)
{
int appDisplayDecimalCount = Program.SettingsGlobal.DisplayDecimalPlacesCount;
if (appDisplayDecimalCount == 3)//0.000
{
inputString = String.Format("{0:#,##0.##0}", input, displayCulture);
}
else if (appDisplayDecimalCount == 2)//0.00
{
inputString = String.Format("{0:#,##0.#0}", input, displayCulture);
}
else if (appDisplayDecimalCount == 1)//0.0
{
inputString = String.Format("{0:#,##0.0}", input, displayCulture);
}
else//appDisplayDecimalCount 0 //0
{
inputString = String.Format("{0:#,##0}", input, displayCulture);
}
}
else
{
inputString = String.Format("{0:#,##0.#0}", input, displayCulture);
}
//Check if worked and return if worked, else return 0
bool itWorked = false;
decimal returnDec = 0.00m;
itWorked = decimal.TryParse(inputString, out returnDec);
if (itWorked)
{
return returnDec;
}
else
{
return 0.00m;
}
}
object number = 12.123345534;
string.Format({"0:00"},number.ToString());

How do I display a decimal value to 2 decimal places?

When displaying the value of a decimal currently with .ToString(), it's accurate to like 15 decimal places, and since I'm using it to represent dollars and cents, I only want the output to be 2 decimal places.
Do I use a variation of .ToString() for this?
decimalVar.ToString("#.##"); // returns ".5" when decimalVar == 0.5m
or
decimalVar.ToString("0.##"); // returns "0.5" when decimalVar == 0.5m
or
decimalVar.ToString("0.00"); // returns "0.50" when decimalVar == 0.5m
I know this is an old question, but I was surprised to see that no one seemed to post an answer that;
Didn't use bankers rounding
Keeps the value as a decimal.
This is what I would use:
decimal.Round(yourValue, 2, MidpointRounding.AwayFromZero);
http://msdn.microsoft.com/en-us/library/9s0xa85y.aspx
decimalVar.ToString("F");
This will:
Round off to 2 decimal places eg. 23.456 → 23.46
Ensure that there
are always 2 decimal places eg. 23 → 23.00; 12.5 → 12.50
Ideal for displaying currency.
Check out the documentation on ToString("F") (thanks to Jon Schneider).
If you just need this for display use string.Format
String.Format("{0:0.00}", 123.4567m); // "123.46"
http://www.csharp-examples.net/string-format-double/
The "m" is a decimal suffix. About the decimal suffix:
http://msdn.microsoft.com/en-us/library/364x0z75.aspx
Given decimal d=12.345; the expressions d.ToString("C") or String.Format("{0:C}", d) yield $12.35 - note that the current culture's currency settings including the symbol are used.
Note that "C" uses number of digits from current culture. You can always override default to force necessary precision with C{Precision specifier} like String.Format("{0:C2}", 5.123d).
If you want it formatted with commas as well as a decimal point (but no currency symbol), such as 3,456,789.12...
decimalVar.ToString("n2");
There's a very important characteristic of Decimal that isn't obvious:
A Decimal 'knows' how many decimal places it has based upon where it came from
The following may be unexpected :
Decimal.Parse("25").ToString() => "25"
Decimal.Parse("25.").ToString() => "25"
Decimal.Parse("25.0").ToString() => "25.0"
Decimal.Parse("25.0000").ToString() => "25.0000"
25m.ToString() => "25"
25.000m.ToString() => "25.000"
Doing the same operations with Double will result in zero decimal places ("25") for all of the above examples.
If you want a decimal to 2 decimal places there's a high likelyhood it's because it's currency in which case this is probably fine for 95% of the time:
Decimal.Parse("25.0").ToString("c") => "$25.00"
Or in XAML you would use {Binding Price, StringFormat=c}
One case I ran into where I needed a decimal AS a decimal was when sending XML to Amazon's webservice. The service was complaining because a Decimal value (originally from SQL Server) was being sent as 25.1200 and rejected, (25.12 was the expected format).
All I needed to do was Decimal.Round(...) with 2 decimal places to fix the problem regardless of the source of the value.
// generated code by XSD.exe
StandardPrice = new OverrideCurrencyAmount()
{
TypedValue = Decimal.Round(product.StandardPrice, 2),
currency = "USD"
}
TypedValue is of type Decimal so I couldn't just do ToString("N2") and needed to round it and keep it as a decimal.
Here is a little Linqpad program to show different formats:
void Main()
{
FormatDecimal(2345.94742M);
FormatDecimal(43M);
FormatDecimal(0M);
FormatDecimal(0.007M);
}
public void FormatDecimal(decimal val)
{
Console.WriteLine("ToString: {0}", val);
Console.WriteLine("c: {0:c}", val);
Console.WriteLine("0.00: {0:0.00}", val);
Console.WriteLine("0.##: {0:0.##}", val);
Console.WriteLine("===================");
}
Here are the results:
ToString: 2345.94742
c: $2,345.95
0.00: 2345.95
0.##: 2345.95
===================
ToString: 43
c: $43.00
0.00: 43.00
0.##: 43
===================
ToString: 0
c: $0.00
0.00: 0.00
0.##: 0
===================
ToString: 0.007
c: $0.01
0.00: 0.01
0.##: 0.01
===================
Math.Round Method (Decimal, Int32)
Very rarely would you want an empty string if the value is 0.
decimal test = 5.00;
test.ToString("0.00"); //"5.00"
decimal? test2 = 5.05;
test2.ToString("0.00"); //"5.05"
decimal? test3 = 0;
test3.ToString("0.00"); //"0.00"
The top rated answer is incorrect and has wasted 10 minutes of (most) people's time.
Mike M.'s answer was perfect for me on .NET, but .NET Core doesn't have a decimal.Round method at the time of writing.
In .NET Core, I had to use:
decimal roundedValue = Math.Round(rawNumber, 2, MidpointRounding.AwayFromZero);
A hacky method, including conversion to string, is:
public string FormatTo2Dp(decimal myNumber)
{
// Use schoolboy rounding, not bankers.
myNumber = Math.Round(myNumber, 2, MidpointRounding.AwayFromZero);
return string.Format("{0:0.00}", myNumber);
}
None of these did exactly what I needed, to force 2 d.p. and round up as 0.005 -> 0.01
Forcing 2 d.p. requires increasing the precision by 2 d.p. to ensure we have at least 2 d.p.
then rounding to ensure we do not have more than 2 d.p.
Math.Round(exactResult * 1.00m, 2, MidpointRounding.AwayFromZero)
6.665m.ToString() -> "6.67"
6.6m.ToString() -> "6.60"
The top-rated answer describes a method for formatting the string representation of the decimal value, and it works.
However, if you actually want to change the precision saved to the actual value, you need to write something like the following:
public static class PrecisionHelper
{
public static decimal TwoDecimalPlaces(this decimal value)
{
// These first lines eliminate all digits past two places.
var timesHundred = (int) (value * 100);
var removeZeroes = timesHundred / 100m;
// In this implementation, I don't want to alter the underlying
// value. As such, if it needs greater precision to stay unaltered,
// I return it.
if (removeZeroes != value)
return value;
// Addition and subtraction can reliably change precision.
// For two decimal values A and B, (A + B) will have at least as
// many digits past the decimal point as A or B.
return removeZeroes + 0.01m - 0.01m;
}
}
An example unit test:
[Test]
public void PrecisionExampleUnitTest()
{
decimal a = 500m;
decimal b = 99.99m;
decimal c = 123.4m;
decimal d = 10101.1000000m;
decimal e = 908.7650m
Assert.That(a.TwoDecimalPlaces().ToString(CultureInfo.InvariantCulture),
Is.EqualTo("500.00"));
Assert.That(b.TwoDecimalPlaces().ToString(CultureInfo.InvariantCulture),
Is.EqualTo("99.99"));
Assert.That(c.TwoDecimalPlaces().ToString(CultureInfo.InvariantCulture),
Is.EqualTo("123.40"));
Assert.That(d.TwoDecimalPlaces().ToString(CultureInfo.InvariantCulture),
Is.EqualTo("10101.10"));
// In this particular implementation, values that can't be expressed in
// two decimal places are unaltered, so this remains as-is.
Assert.That(e.TwoDecimalPlaces().ToString(CultureInfo.InvariantCulture),
Is.EqualTo("908.7650"));
}
You can use system.globalization to format a number in any required format.
For example:
system.globalization.cultureinfo ci = new system.globalization.cultureinfo("en-ca");
If you have a decimal d = 1.2300000 and you need to trim it to 2 decimal places then it can be printed like this d.Tostring("F2",ci); where F2 is string formating to 2 decimal places and ci is the locale or cultureinfo.
for more info check this link
http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx
https://msdn.microsoft.com/en-us/library/dwhawy9k%28v=vs.110%29.aspx
This link explains in detail how you can handle your problem and what you can do if you want to learn more. For simplicity purposes, what you want to do is
double whateverYouWantToChange = whateverYouWantToChange.ToString("F2");
if you want this for a currency, you can make it easier by typing "C2" instead of "F2"
The most applicable solution is
decimalVar.ToString("#.##");
Double Amount = 0;
string amount;
amount=string.Format("{0:F2}", Decimal.Parse(Amount.ToString()));
If you need to keep only 2 decimal places (i.e. cut off all the rest of decimal digits):
decimal val = 3.14789m;
decimal result = Math.Floor(val * 100) / 100; // result = 3.14
If you need to keep only 3 decimal places:
decimal val = 3.14789m;
decimal result = Math.Floor(val * 1000) / 1000; // result = 3.147
var arr = new List<int>() { -4, 3, -9, 0, 4, 1 };
decimal result1 = arr.Where(p => p > 0).Count();
var responseResult1 = result1 / arr.Count();
decimal result2 = arr.Where(p => p < 0).Count();
var responseResult2 = result2 / arr.Count();
decimal result3 = arr.Where(p => p == 0).Count();
var responseResult3 = result3 / arr.Count();
Console.WriteLine(String.Format("{0:#,0.000}", responseResult1));
Console.WriteLine(String.Format("{0:#,0.0000}", responseResult2));
Console.WriteLine(String.Format("{0:#,0.00000}", responseResult3));
you can put as many 0 as you want.

Categories

Resources