Decimal ToString() conversion issue in C# - c#

I am facing a problem when I try to convert decimal? to string. Scenario is
decimal decimalValue = .1211;
string value = (decimalValue * 100).ToString();
Current Result : value = 12.1100
Expected Result : value = 12.11
Please let me know, what could be reason for this.

Decimal preserves any trailing zeroes in a Decimal number. If you want two decimal places instead:
decimal? decimalValue = .1211m;
string value = ((decimal)(decimalValue * 100)).ToString("#.##")
http://msdn.microsoft.com/en-us/library/0c899ak8.aspx
or
string value = ((decimal)(decimalValue * 100)).ToString("N2")
http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx
From System.Decimal:
A decimal number is a floating-point
value that consists of a sign, a
numeric value where each digit in the
value ranges from 0 to 9, and a
scaling factor that indicates the
position of a floating decimal point
that separates the integral and
fractional parts of the numeric value.
The binary representation of a Decimal
value consists of a 1-bit sign, a
96-bit integer number, and a scaling
factor used to divide the 96-bit
integer and specify what portion of it
is a decimal fraction. The scaling
factor is implicitly the number 10,
raised to an exponent ranging from 0
to 28. Therefore, the binary
representation of a Decimal value is
of the form, ((-296 to 296) / 10(0 to
28)), where -296-1 is equal to
MinValue, and 296-1 is equal to
MaxValue.
The scaling factor also preserves any
trailing zeroes in a Decimal number.
Trailing zeroes do not affect the
value of a Decimal number in
arithmetic or comparison operations.
However, >>trailing zeroes can be
revealed by the ToString method if an
appropriate format string is applied<<.
Remarks:
the decimal multiplication needs to be casted to decimal, because Nullable<decimal>.ToString has no format provider
as Chris pointed out you need to handle the case that the Nullable<decimal> is null. One way is using the Null-Coalescing-Operator:
((decimal)(decimalValue ?? 0 * 100)).ToString("N2")
This article from Jon Skeet is worth reading:
Decimal floating point in .NET (seach for keeping zeroes if you're impatient)

Since you using Nullable<T> as your decimal, Nullable<T>.ToString() method doesn't have overloading takes parameters that you can use for formatting.
Instead of, you can explicitly cast it to decimal and you can use .ToString() method for formatting.
Just use "0.00" format in your .ToString() method.
decimal? decimalValue = .1211M;
string value = ((decimal)(decimalValue * 100)).ToString("0.00");
Console.WriteLine(value);
Output will be;
12.11
Here is a DEMO.
As an alternative, you can use Nullable<T>.Value without any conversation like;
string value = (decimalValue * 100).Value.ToString("0.00");
Check out for more information from Custom Numeric Format Strings

Alternatively, you can specify the format "F2", like so: string val = decVal.ToString("F2") as this specifies 2 decimal places.

Use the fixed-point ("F) format specifier .
string value = (decimalValue * 100).ToString("F");
The default precision specifier is based on value of NumberFormatInfo.NumberDecimalDigits property which by default has value 2. So if don't specify a digit aftyer "F" , it by default specifies two decimal digits.
F0 - No decimal places
F1 - One decimal place

In case you do not want to limit to a certain amount of decimal digits:
decimal? decimalValue = .1211;
string value = decimalValue == null
? "0"
: decimalValue == 0
? "0"
: (decimalValue * 100).ToString().TrimEnd('0');
This will trim any (if any) trailing zeroes of the string and also return "0" if decimalValue is null. If the value is 0 then "0" is returned without trimming.

String.Format("{0:0.00}", decimalValue * 100);
You can use .Format() as an alternative to .ToString("0.00").

Since decimal? does not have a ToString(string format) overload, the easiest way is to use String.Format instead which will provide consistent results with the null case for decimalValue as well (resulting in an empty string) when compared to your original code:
string value = String.Format("{0:#.##}", decimalValue * 100);
But there are some other considerations for other numbers that you weren't clear on.
If you have a number that does not produce a value greater than 0, does it show a leading zero? That is, for 0.001211, does it display as 0.12 or .12? If you want the leading zero, use this instead (notice the change from #.## to 0.##):
string value = String.Format("{0:0.##}", decimalValue * 100);
If you have more than 2 significant decimal places, do you want those displayed? So if you had .12113405 would it display as 12.113405? If so use:
string value = String.Format("{0:#.############}", decimalValue * 100);
(honestly, I think there must be a better formatting string than that, especially as it only supports 12 decimal places)
And of course if you want both leading zeros and multiple decimal places, just combine the two above:
string value = String.Format("{0:0.############}", decimalValue * 100);

Related

How to add precision to decimal value

I want to add precision to the decimal value. For example, I have this value:
decimal number = 10;
I want to make it 10.00. I don't want to convert it to string like number.ToString("#.00")
Currently, I have this method:
decimal CalculatePrecision(decimal value, int precision)
{
var storedCalculated = decimal.Divide(1, Convert.ToDecimal(Math.Pow(10, precision)));
return value + storedCalculated - storedCalculated;
}
Is there any good solution for this?
You can't. 10 and 10.00 are the same number. Only the "presentation" is different. Both "presentations" are strings. The actual number look different. If you need to change the presentation, convert to string.
How about
decimal d = 10;
d += 0.00M;
Console.WriteLine(d);
Try reference
Math.Round not keeping the trailing zero
How do I display a decimal value to 2 decimal places?

Exponents in C#

int trail = 14;
double mean = 14.00000587000000;
double sd = 4.47307944700000;
double zscore = double.MinValue;
zscore = (trail - mean) / sd; //zscore at this point is exponent value -1.3122950464645662E-06
zscore = Math.Round(zscore, 14); //-1.31229505E-06
Math.Round() also keeps the exponent value. should zscore.ToString("F14") be used instead of Math.Round() function to convert it to non-exponent value? Please explain.
These are completely independant concerns.
Math.Round will actually return a new value, rounded to the specified decimal (ar at least, as near as one can do with floating point).
You can reuse this result value anywhere, and show it with 16 decimals precision if you want, but it's not supposed to be the same as the original one.
The fact that it is displayed with exponent notation or not has nothing to do with Round.
When you use ToString("F14") on a number, this is a display specification only, and does not modify the underlying value in any way. The underlying value might be a number that would or would not display as exponential notation otherwise, and may or may actually have 14 significant digits.
It simply forces the number to be displayed as a full decimal without exponent notation, with the number of digits specified. So it seems to be what you actually want.
Examples :
(executable online here : http://rextester.com/PZXDES55622)
double num = 0.00000123456789;
Console.WriteLine("original :");
Console.WriteLine(num.ToString());
Console.WriteLine(num.ToString("F6"));
Console.WriteLine(num.ToString("F10"));
Console.WriteLine(num.ToString("F14"));
Console.WriteLine("rounded to 6");
double rounded6 = Math.Round(num, 6);
Console.WriteLine(rounded6.ToString());
Console.WriteLine(rounded6.ToString("F6"));
Console.WriteLine(rounded6.ToString("F10"));
Console.WriteLine(rounded6.ToString("F14"));
Console.WriteLine("rounded to 10");
double rounded10 = Math.Round(num, 10);
Console.WriteLine(rounded10.ToString());
Console.WriteLine(rounded10.ToString("F6"));
Console.WriteLine(rounded10.ToString("F10"));
Console.WriteLine(rounded10.ToString("F14"));
will output:
original :
1,23456789E-06
0,000001
0,0000012346
0,00000123456789
rounded to 6
1E-06
0,000001
0,0000010000
0,00000100000000
rounded to 10
1,2346E-06
0,000001
0,0000012346
0,00000123460000

How can I convert fraction to double or decimal?

Case:
double x = Math.Pow(Convert.ToDouble(0.07003 + 1 ),(1/12));
Console.WriteLine(x);
Output:
1
The above output is incorrect, because the result of x is 1 instead of 1.005657
How to convert 1/12 in a format that it gives fractional value and is accepted by Math.Pow().
And the real problem is division of 1 by 12 (1/12) which gives value 0 (instead of 0,083333...).
Try this:
double x = Math.Pow(Convert.ToDouble(0.07003 + 1 ),(1/12d));
This makes 12 a double which makes the result of 1/12 a double. So instead of getting 0 from that division the result will be 0.0833333333333333.
The literals 1 and 12 are both integers, so 1/12 is an integer division, giving an integer result (0). Change at least one literal to double or decimal to perform a floating point division.
To make a number literal a double, add decimal places (e.g. 1.0) or 'D' suffix (1D). To make it a decimal, add 'M' suffix (1M).

Parsing json string number losing minimum precision

i'm working in a C# (Unity3D compatible = .NET 2.0) Json library and i'm having precision problems. Firstly i have this logic in order to parse number strings:
...
string jsonPart ="-1.7555215491128452E-19"
enter code here
long longValue = 0;
if (long.TryParse(jsonPart, NumberStyles.Any, CultureInfo.InvariantCulture, out longValue))
{
if (longValue > int.MaxValue || longValue < int.MinValue)
{
jsonPartValue = new JsonBasic(longValue);
}
else
{
jsonPartValue = new JsonBasic((int)longValue);
}
}
else
{
decimal decimalValue = 0;
if (decimal.TryParse(jsonPart, NumberStyles.Any, CultureInfo.InvariantCulture, out decimalValue))
{
jsonPartValue = new JsonBasic(decimalValue);
}
}
...
The problem comes because decimal type is not the best type always for big decimal numbers. I have an output log to show you the problem (using .ToString()):
String = "-1.7555215491128452E-19"
Float Parsed : -1.755522E-19
Double parsed : -1.75552154911285E-19
Decimal Parsed : -0.0000000000000000001755521549
but on the other way , this examples with decimal type is the right one:
String = "0.1666666666666666666"
Float Parsed : 0.1666667
Double parsed : 0.166666666666667
Decimal Parsed : 0.1666666666666666666
String = "-1.30142114406914976E17"
Float Parsed : -1.301421E+17
Double parsed : -1.30142114406915E+17
Decimal Parsed : -130142114406914976
I suppost there is many other cases that can balance to one type or another.
Is there any smart way to parse it loosing minimum precision?
The difference you are seeing is because, although decimal can hold up to 28 or 29 digits of precision compared to double's 15 or 16 digits, its range is much lower than double.
A decimal has a range of (-7.9 x 10^28 to 7.9 x 10^28) / (10^(0 to 28))
A decimal stores ALL the digits, including zeros after a decimal point which is preceeded by a zero (e.g. 0.00000001) - i.e. it doesn't store numbers using exponential format.
A double has a range of ±5.0 × 10^−324 to ±1.7 × 10^308
A double can store a number using exponential format which means it doesn't have to store the leading zeroes in a number like 0.0000001.
The consequence of this is that for numbers that are at the edges of the decimal range, it actually has less precision than a double.
For example, consider the number -1.7555215491128452E-19:
Converting that to non-exponential notation you get:
-0.00000000000000000017555215491128452
1 2 3
12345678901234567890123456789012345
You can see that the number of decimal digits of that is 35, which exceeds the range of a decimal.
As you have observed, when you print that number out after storing it in a decimal, you get:
-0.0000000000000000001755521549
1 2
1234567901234567890123456789
which is giving you only 29 digits, as per Microsoft's specification.
A double, however, stores its numbers using exponential notation which means that it doesn't store all the leading zeroes, which allows it to store that particular number with greater precision.
For example, a double stores -0.00000000000000000017555215491128452 as an exponential number with 15 or 16 digits of precision.
If you take 15 digits of precision from the above number you get:
-0.000000000000000000175552154911285
1
123456789012345
which is indeed what is printed out if you do this:
double d = -1.7555215491128452E-19;
Console.WriteLine(d.ToString("F35"));

Double type strange behavior while concatenating with String or Converting to String

I have logging functionality in project which compares objects value and displays differences but i have a scenarion i have latitude and longitude values in double data type but when i concatenate it with string or convert it to string i am getting strange behaviour as it is showing the same value in both variables which is totally not understandable how it is happening.
Here is the code:
double value1 = -6.2845230102539063;
double value2 = -6.2845230102539098;
if (!object.Equals(value1, value2))
{
var result = value2 + " to " + value1;
Console.WriteLine(result);
}
Console.ReadLine();
Expected Output :
-6.2845230102539098 to -6.2845230102539063
Actual Output :
-6.28452301025391 to -6.28452301025391
Here is DEMO FIDDLE:
https://dotnetfiddle.net/0XM3Da
What is happening here?
From MSDN: http://msdn.microsoft.com/en-us/library/678hzkk9.aspx
Double has a precision of 15-16 digits. You've exceeded that limit. You should use Decimal instead. See here for details: Can C# store more precise data than doubles?
This is addressed in #LukeH's answer to "Formatting doubles for output in C#":
The problem is that .NET will always round a double to 15 significant
decimal digits before applying your formatting, regardless of the
precision requested by your format and regardless of the exact decimal
value of the binary number.
Using the DoubleConverter class linked to in that answer, we get
var x = -6.2845230102539063;
var y = -6.2845230102539098;
Console.WriteLine(x == y);
Console.WriteLine(x);
Console.WriteLine(y);
Console.WriteLine(DoubleConverter.ToExactString(x));
Console.WriteLine(DoubleConverter.ToExactString(y));
which prints
False
-6.28452301025391
-6.28452301025391
-6.28452301025390625
-6.284523010253909802713678800500929355621337890625
Or you can use the G17 format specification
Console.WriteLine(x.ToString("G17"));
Console.WriteLine(y.ToString("G17"));
which will give you
-6.2845230102539063
-6.2845230102539098
From: http://msdn.microsoft.com/en-us/library/kfsatb94(v=vs.110).aspx
'By default, the return value only contains 15 digits of precision although a maximum of 17 digits is maintained internally.'
So it knows that they are not the same size, but doesn't display them that way.
A Double value has up to 15 decimal digits of precision, you can refer to detail explanation http://msdn.microsoft.com/zh-cn/library/system.double(v=vs.110).aspx
Have you tried the decimal data type. It gives you an exact representation of numbers...for banking and stock markets I suppose. And you could reduce the mantissa to a certain length (perhaps 18).

Categories