I want to pad my number decimal points to 6.
So 0.0345 --> become 0.034500
0.6 --> become 0.600000
But no matter what decimal values I put in Math.Round, my code below only pads the decimal points to 5
var amount = Math.Round(0.0345, 6, MidpointRounding.AwayFromZero);
var amount1 = Math.Round(0.0345, 7, MidpointRounding.AwayFromZero);
Result:
amount = 0.03450
amount1 = 0.03450
Thank you.
There are two possibilities; if amount is of type decimal, you can add zero:
decimal amount = 0.0345m;
amount += 0.000000m;
Console.Write(amount);
Outcome:
0.034500
Or represent amount in desired format:
decimal amount = 0.0345m;
Console.Write(amount.ToString("F6"));
If amount is of type double or float then 0.034500 == 0.0345 and all you can do is to format when representing amount as a string:
double amount = 0.0345;
...
// F6 format string stands for 6 digits after the decimal point
Console.Write(amount.ToString("F6"));
Edit: In order create such kind of zero you can use
public static decimal Zero(int zeroesAfterDecimalPoint) {
if (zeroesAfterDecimalPoint < 0 || zeroesAfterDecimalPoint > 29)
throw new ArgumentOutOfRangeException(nameof(zeroesAfterDecimalPoint));
int[] bits = new int[4];
bits[3] = zeroesAfterDecimalPoint << 16;
return new decimal(bits);
}
And so have MyRound method:
private static Decimal MyRound(Decimal value, int digits) {
return Math.Round(value, digits, MidpointRounding.AwayFromZero) +
Zero(digits);
}
private static Decimal MyRound(double value, int digits) =>
MyRound((decimal)value, digits);
...
decimal amount = 0.0345m;
Console.WriteLine(MyRound(amount, 6));
Console.WriteLine(MyRound(0.0345, 7)); // let's provide double and 7 digits
Outcome:
0.034500
0.0345000
You can simply use format string with six decimals
decimal value = 0.6m;
Console.WriteLine("{0:0.000000}", value);
value = 0.0345m;
Console.WriteLine("{0:0.000000}", value);
// output
// 0.600000
// 0.034500
It only works this way if the incoming value is double.
double doubleParsing = 0.0345;
decimal amount = decimal.Parse(doubleParsing.ToString());
amount += 0.000000m;
var result = amount.ToString("F5");
Related
This question already has answers here:
Round a decimal number to the first decimal position that is not zero
(5 answers)
Closed 2 years ago.
I have an overloaded extension method which rounds either a decimal or double to N number of decimal places and it works perfectly.
public static class NumberExtensions
{
public static string ToStringNDecimalPlaces(this double dbValue, int nDecimal)
{
return dbValue.ToString("N" + nDecimal);
}
public static string ToStringNDecimalPlaces(this decimal dbValue, int nDecimal)
{
return dbValue.ToString("N" + nDecimal);
}
}
My question is, I want to create another called something like, "ToStringFirstDecimalPlace" or something like that which takes the decimal value and rounds it to the first logical decimal value after the 0s. Let me give some, this is how I would like the method to work:
e.g.
0.000345879 = 0.0003
0.019356 = 0.02
0.1 = 0.1
So it ignores the leading 0s and takes the nth to be the first logical number that makes sense instead of just rounding to 0.0 for example.
Well can't you count the number of zeroes and then format accordingly?
Example for positive values:
string result;
if(dbValue != 0)
{
int count = 0;
var copyDb = dbValue;
while(copyDb < 1)
{
copyDb *= 10;
count++;
}
result = dbValue.ToStringNDecimalPlaces(count);
}
else
{
result = "0";
}
You can write the following function to achieve this:
public static string ToStringNDecimalPlacesIgnoreZeros(this double dbValue)
{
var value = dbValue - Math.Floor(dbValue); // Get rid of integer digits
int position = 0;
while (value > 0 && Math.Floor(value) == 0)
{
value = value * 10;
position += 1;
}
if (value == 0)
return dbValue.ToString("N");
else
return dbValue.ToStringNDecimalPlaces( position);
}
First, assume that the input is between 0 and 1, inclusive. If not, subtract the integer part (and if negative, negate the remainder) before rounding the rest (this process can be reversed after the rounding is complete). Then, do something like this:
RountToFirstLogical(input)
1. place = 1
2. while place > input
3. place = place / 10
4. input = round(input/place) * place
5. return input
Examples:
input=0.000345879
place=1, 0.1, 0.01, 0.001, 0.0001
input/place = 3.45879
round(input/place) = 3
round(input/place) * place = 0.0003
input=0.019356
place=1, 0.1, 0.01
input/place = 1.9356
round(input/place) = 2
round(input/place)*place = 0.02
input=0.1
place=1, 0.1
input/place=1
round(input/place)=1
round(input/place)*place=0.1
If small number then it worked, but with larger number then it was wrong. My example code below.
public void TestZZZZZZZZZ()
{
ulong val = ulong.MaxValue; // val = 18446744073709551615
string s = string.Format("{0}", val);
double d = Convert.ToDouble(s);
ulong result = ((ulong)d; // result = 0 <-- WRONG
Assert.AreEqual(val, result);
}
Some test data result:
If val = 1229 then it OK
If val = 90071992549900000 then it OK.
If val = 90071992549900001 then result = 90071992549900000
If val = 90071992549900009 then result = 90071992549900016
Is there any my wrong? please help.
Thanks!
That's because long holds 64 bits of data, and significant precision of double is only 53 bits.
double Have precision of 16 digits. So test your number for 16 digits.
ulong val = 1234567890123456; // 16 digits
double d = val;
ulong result = (ulong)d;
Console.WriteLine(val == result); // prints true
After this you will loose precision.
ulong val = 12345678901234567; // 17 digits
double d = val;
ulong result = (ulong)d;
Console.WriteLine(val == result); // prints false
From Msdn:
Long:Signed 64-bit integer
Double:64-bit floating (15-16 digits Precision)
So result is not same.
So if you have just 16 digits your assert is ok.
Like M.kazem Akhgary answer.
My solution here was use decimal to contain value for converting (instead double).
Thanks for all your supporting!
Trong.
I have an input type integer that represents a number that needs to be converted to double between 1-100, and the rest is decimal precision.
Example: 1562 -> 15.62 ; 198912 -> 19.8912
Right now, I tried a conversion to string, count the number of characters, take 2 to check how many decimals I have and depending of the result "create" a composite string to get a valid double...
Any idea of there is a better way of resolving convert-precision on runtime.
What about this:
int value = 1562;
decimal d = value;
while (d > 100) {
d /= 10;
}
You can use LINQ Skip and Take like:
string str = "198912";
string newStr = string.Format("{0}.{1}", new string(str.Take(2).ToArray()), new string(str.Skip(2).ToArray()));
double d = double.Parse(newStr, CultureInfo.InvariantCulture);
You can add the checks for length on original string, and also use double.TryParse to see if you get valid values.
If you have an int to begin with then you can use decimal, which would provide you more accurate conversion. Like:
int number = 1562123123;
decimal decimalNumber = number;
while (decimalNumber > 100)
{
decimalNumber /= 10;
}
Here is a mathematical solution. The line lg = Math.Max(lg, 0); changes "2" to return "2.0" instead of "20.0" but I guess that depends on your needs for single digit numbers.
static double ToDoubleBetween1And100(int num)
{
var lg = Math.Floor(Math.Log10(num)) - 1;
lg = Math.Max(lg, 0);
return ((double)num) / Math.Pow(10, lg);
}
I need to truncate a number to 2 decimal places, which basically means
chopping off the extra digits.
Eg:
2.919 -> 2.91
2.91111 -> 2.91
Why? This is what SQL server is doing when storing a number of a
particular precision. Eg, if a column is Decimal(8,2), and you try to
insert/update a number of 9.1234, the 3 and 4 will be chopped off.
I need to do exactly the same thing in c# code.
The only possible ways that I can think of doing it are either:
Using the stringformatter to "print" it out only
two decimal places, and then converting it to a decimal,
eg:
decimal tooManyDigits = 2.1345
decimal ShorterDigits = Convert.ToDecimal(tooManyDigits.ToString("0.##"));
// ShorterDigits is now 2.13
I'm not happy with this because it involves a to-string and then
another string to decimal conversion which seems a bit mad.
Using Math.Truncate (which only accepts an integer), so I
can multiply it by 100, truncate it, then divide by 100. eg:
decimal tooLongDecimal = 2.1235;
tooLongDecimal = Math.Truncate(tooLongDecimal * 100) / 100;
I'm also not happy with this because if tooLongDecimal is 0,
I'll get a divide by 0 error.
Surely there's a better + easier way! Any suggestions?
You've answered the question yourself; it seems you just misunderstood what division by zero means. The correct way to do this is to multiply, truncate, then devide, like this:
decimal TruncateTo100ths(decimal d)
{
return Math.Truncate(d* 100) / 100;
}
TruncateTo100ths(0m); // 0
TruncateTo100ths(2.919m); // 2.91
TruncateTo100ths(2.91111m); // 2.91
TruncateTo100ths(2.1345m); // 2.13
There is no division by zero here, there is only division by 100, which is perfectly safe.
The previously offered mathematical solutions are vulnerable to overflow with large numbers and/or a large number of decimal places. Consider instead the following extension method:
public static decimal TruncateDecimal(this decimal d, int decimals)
{
if (decimals < 0)
throw new ArgumentOutOfRangeException("decimals", "Value must be in range 0-28.");
else if (decimals > 28)
throw new ArgumentOutOfRangeException("decimals", "Value must be in range 0-28.");
else if (decimals == 0)
return Math.Truncate(d);
else
{
decimal integerPart = Math.Truncate(d);
decimal scalingFactor = d - integerPart;
decimal multiplier = (decimal) Math.Pow(10, decimals);
scalingFactor = Math.Truncate(scalingFactor * multiplier) / multiplier;
return integerPart + scalingFactor;
}
}
Usage:
decimal value = 18446744073709551615.262626263m;
value = value.TruncateDecimal(6); // Result: 18446744073709551615.262626
I agree with p.s.w.g. I had the similar requirement and here is my experience and a more generalized function for truncating.
http://snathani.blogspot.com/2014/05/truncating-number-to-specificnumber-of.html
public static decimal Truncate(decimal value, int decimals)
{
decimal factor = (decimal)Math.Pow(10, decimals);
decimal result = Math.Truncate(factor * value) / factor;
return result;
}
Using decimal.ToString('0.##') also imposes rounding:
1.119M.ToString("0.##") // -> 1.12
(Yeah, likely should be a comment, but it's hard to format well as such.)
public static decimal Rounding(decimal val, int precision)
{
decimal res = Trancating(val, precision + 1);
return Math.Round(res, precision, MidpointRounding.AwayFromZero);
}
public static decimal Trancating(decimal val,int precision)
{
if (val.ToString().Contains("."))
{
string valstr = val.ToString();
string[] valArr = valstr.Split('.');
if(valArr[1].Length < precision)
{
int NoOfZeroNeedToAdd = precision - valArr[1].Length;
for (int i = 1; i <= NoOfZeroNeedToAdd; i++)
{
valstr = string.Concat(valstr, "0");
}
}
if(valArr[1].Length > precision)
{
valstr = valArr[0] +"."+ valArr[1].Substring(0, precision);
}
return Convert.ToDecimal(valstr);
}
else
{
string valstr=val.ToString();
for(int i = 0; i <= precision; i++)
{
if (i == 1)
valstr = string.Concat(valstr, ".0");
if(i>1)
valstr = string.Concat(valstr, "0");
}
return Convert.ToDecimal(valstr);
}
}
How can I display the number with just the 2 not=zero decimals?
Example:
For 0.00045578 I want 0.00045 and for 1.0000533535 I want 1.000053
There is no built in formatting for that.
You can get the fraction part of the number and count how many zeroes there are until you get two digits, and put together the format from that. Example:
double number = 1.0000533535;
double i = Math.Floor(number);
double f = number % 1.0;
int cnt = -2;
while (f < 10) {
f *= 10;
cnt++;
}
Console.WriteLine("{0}.{1}{2:00}", i, new String('0', cnt), f);
Output:
1.000053
Note: The given code only works if there actually is a fractional part of the number, and not for negative numbers. You need to add checks for that if you need to support those cases.
My solution would be to convert the number to a string. Search for the ".", then count zeroes till you find a non-zero digit, then take two digits.
It's not an elegant solution, but I think it will give you consistent results.
Try this function, using parsing to find the # of fractional digits rather than looking for zeros (it works for negative #s as well):
private static string GetTwoFractionalDigitString(double input)
{
// Parse exponential-notation string to find exponent (e.g. 1.2E-004)
double absValue = Math.Abs(input);
double fraction = (absValue - Math.Floor(absValue));
string s1 = fraction.ToString("E1");
// parse exponent peice (starting at 6th character)
int exponent = int.Parse(s1.Substring(5)) + 1;
string s = input.ToString("F" + exponent.ToString());
return s;
}
You can use this trick:
int d, whole;
double number = 0.00045578;
string format;
whole = (int)number;
d = 1;
format = "0.0";
while (Math.Floor(number * Math.Pow(10, d)) / Math.Pow(10, d) == whole)
{
d++;
format += "0";
}
format += "0";
Console.WriteLine(number.ToString(format));