string.format(format,doubleValue) , precision lost - c#

I have this double value:
var value = 52.30298270000003
and when I convert it to string, it losses its precision:
var str = string.Format("{0} some text...", value);
Console.WriteLine(str); // output: 52.3029827
The number of precision on my double value may be changed at run-time. How can I force the string.Format method to use all precision?

You want to use the R format specifier
From the MSDN
Result: A string that can round-trip to an identical number.
Supported by: Single, Double, and BigInteger.
Precision specifier: Ignored.
More information: The Round-trip ("R") Format Specifier.
String.Format("{0:R} some text...", value)
will give you
52.30298270000003 some text...

Try this:
var value = 52.30298270000003;
var str = string.Format("{0} some text...", value.ToString("R"));
Console.WriteLine(str); // output: 52.3029827
The MSDN documnetation has the following to say about the ToString method of Singles and Doubles and using ToString("R"):
By default, the return value only contains 7 digits of precision
although a maximum of 9 digits is maintained internally. If the value
of this instance has greater than 7 digits, ToString(String) returns
PositiveInfinitySymbol or NegativeInfinitySymbol instead of the
expected number. If you require more precision, specify format with
the "G9" format specification, which always returns 9 digits of
precision, or "R", which returns 7 digits if the number can be
represented with that precision or 9 digits if the number can only be
represented with maximum precision.

Related

string format money , [duplicate]

I need to display a number with commas and a decimal point.
Eg:
Case 1 : Decimal number is 432324 (This does not have commas or decimal points).
Need to display it as: 432,324.00.
Not: 432,324
Case 2 : Decimal number is 2222222.22 (This does not have commas).
Need to display it as: 2,222,222.22
I tried ToString("#,##0.##"), but it is not formatting it correctly.
int number = 1234567890;
number.ToString("#,##0.00");
You will get the result 1,234,567,890.00.
Maybe you simply want the standard format string "N", as in
number.ToString("N")
It will use thousand separators, and a fixed number of fractional decimals. The symbol for thousands separators and the symbol for the decimal point depend on the format provider (typically CultureInfo) you use, as does the number of decimals (which will normally by 2, as you require).
If the format provider specifies a different number of decimals, and if you don't want to change the format provider, you can give the number of decimals after the N, as in .ToString("N2").
Edit: The sizes of the groups between the commas are governed by the
CultureInfo.CurrentCulture.NumberFormat.NumberGroupSizes
array, given that you don't specify a special format provider.
Try with
ToString("#,##0.00")
From MSDN
*The "0" custom format specifier serves as a zero-placeholder symbol. If the value that is being formatted has a digit in the position where the zero appears in the format string, that digit is copied to the result string; otherwise, a zero appears in the result string. The position of the leftmost zero before the decimal point and the rightmost zero after the decimal point determines the range of digits that are always present in the result string.
The "00" specifier causes the value to be rounded to the nearest digit preceding the decimal, where rounding away from zero is always used. For example, formatting 34.5 with "00" would result in the value 35.*
I had the same problem. I wanted to format numbers like the "General" format in spreadsheets, meaning show decimals if they're significant, but chop them off if not. In other words:
1234.56 => 1,234.56
1234 => 1,234
It needs to support a maximum number of places after the decimal, but don't put trailing zeros or dots if not required, and of course, it needs to be culture friendly. I never really figured out a clean way to do it using String.Format alone, but a combination of String.Format and Regex.Replace with some culture help from NumberFormatInfo.CurrentInfo did the job (LinqPad C# Program).
string FormatNumber<T>(T number, int maxDecimals = 4) {
return Regex.Replace(String.Format("{0:n" + maxDecimals + "}", number),
#"[" + System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator + "]?0+$", "");
}
void Main(){
foreach (var test in new[] { 123, 1234, 1234.56, 123456.789, 1234.56789123 } )
Console.WriteLine(test + " = " + FormatNumber(test));
}
Produces:
123 = 123
1234 = 1,234
1234.56 = 1,234.56
123456.789 = 123,456.789
1234.56789123 = 1,234.5679
Try with
ToString("#,##0.###")
Produces:
1234.55678 => 1,234.556
1234 => 1,234
For Razor View:
$#string.Format("{0:#,0.00}",item.TotalAmount)
CultureInfo us = new CultureInfo("en-US");
TotalAmount.ToString("N", us)
Your question is not very clear but this should achieve what you are trying to do:
decimal numericValue = 3494309432324.00m;
string formatted = numericValue.ToString("#,##0.00");
Then formatted will contain: 3,494,309,432,324.00
All that is needed is "#,0.00", c# does the rest.
Num.ToString("#,0.00"")
The "#,0" formats the thousand separators
"0.00" forces two decimal points
If you are using string variables you can format the string directly using a : then specify the format (e.g. N0, P2, etc).
decimal Number = 2000.55512016465m;
$"{Number:N}" #Outputs 2,000.55512016465
You can also specify the number of decimal places to show by adding a number to the end like
$"{Number:N1}" #Outputs 2,000.5
$"{Number:N2}" #Outputs 2,000.55
$"{Number:N3}" #Outputs 2,000.555
$"{Number:N4}" #Outputs 2,000.5551
string Mynewcurrency = DisplayIndianCurrency("7743450.00");
private string DisplayIndianCurrency(string EXruppesformate)
{
string fare = EXruppesformate;
decimal parsed = decimal.Parse(fare, CultureInfo.InvariantCulture);
CultureInfo hindi = new CultureInfo("en-IN");
// string text = string.Format(hindi, "{0:c}", parsed);if you want <b>Rs 77,43,450.00</b>
string text = string.Format(hindi, "{0:N}", parsed); //if you want <b>77,43,450.00</b>
return ruppesformate = text;
}
For anyone looking at this now, and getting the "No overload for method 'ToString' takes 1 argument" when using:
TotalNumber.ToString("N")
My solution has been to use :
TotalNumber.Value.ToString("N")
I often get stuck on this when working directly inside an MVC View, the following wasn't working:
#Model.Sum(x => x.Number).ToString("N")
Whereas this works:
#Model.Sum(x => x.Number).Value.ToString("N")

Conversion error parsing number formatted with a comma as the number group separator

In mvc I have formatted a numeric value using a comma as the number group separator as is specified in the Indian numbering system:
PaymentReceived = String.Format(new CultureInfo("en-IN", true), "{0:n}", t.PaymentReceived)
Later, I need to parse the string back to a numeric value. Here the FieldValue is of type long, while the right side value is of type string. How do I get the conversion to long?
I already have tried to do he following, but this is throwing an error message (the input string was not in correct format):
FieldValue = Convert.ToInt64( String.Format(new CultureInfo("en-IN", true), "{0:n}", t1.FieldValue))
As pointed out in the comment, you do not need to format a string with commas to convert it to a long. The commas are purely a presentation issue and None of the primitive number data types(int, long, double...) will maintain them.
To convert the string to long, do this.
FieldValue = Convert.ToInt64(t1.FieldValue)
To display the value as a comma separated number, do this
string formattedString = FieldValue.ToString("N0")
Your problem is not with the number group separator in your string. Your problem is that, when you formatted your number, you used the "{0:n}" format but did not specify a precision. From the docs:
If the precision specifier is omitted, the number of decimal places is defined by the current NumberFormatInfo.NumberDecimalDigits property.
For "en-IN" the default number of digits is 2. Thus your number, despite being a long, is being formatted with decimal digits. I.e. if you do:
long val = 1111111011;
var s = String.Format(new CultureInfo("en-IN", true), "{0:n0}", val);
Console.WriteLine(s);
The result looks like 1,11,11,11,011.00.
Later, you try to parse the string back to a long -- which throws a FormatException. The string is in an invalid format for a long because it contains a decimal point while long can only have integer values.
To avoid this problem, you could:
Format the initial value without a decimal point by using a precision of zero:
String.Format(new CultureInfo("en-IN", true), "{0:n0}", t.PaymentReceived)
Parse to decimal and round:
(long)Math.Round(decimal.Parse(s, new CultureInfo("en-IN", t.PaymentReceived)));

Format decimal number with custom amount of digits after comma

I have this custom extension that should format a decimal number with a custom amount of digits after comma.
public static decimal FormatDecimal(this decimal value, int decimalSeparator = 2)
{
decimal returnValue = Math.Round(value, decimalSeparator, MidpointRounding.AwayFromZero);
return returnValue;
}
The problem is that doesn't work as expected.
If I do like this:
decimal number = 12345;
and then:
decimal formatedNumber = number.FormatDecimal(2);
the result should be:
12345.00
instead the result is:
12345
What I am doing wrong?
Here's the extension function working
public static string FormatDecimal(this decimal value, int decimalSeparator = 2)
{
return value.ToString(string.Format("0.{0}", new string('0', decimalSeparator)));
}
I think the right way is to using The "0" custom format specifier;
Replaces the zero with the corresponding digit if one is present;
otherwise, zero appears in the result string.
For example;
decimal d = 12345;
Console.WriteLine(d.ToString("#.00")); // 12345.00
You're probably looking to format the string representation of your decimal instead. Try this:
decimal myNumber = 12345.67m;
string formattedNumber = myNumber.ToString("N3");
Console.WriteLine(formattedNumber); // Prints "12345.670"
See here for more information: https://msdn.microsoft.com/en-us/library/dwhawy9k%28v=vs.110%29.aspx
From MSDN:
Standard numeric format strings are used to format common numeric types. A standard numeric format string takes the form Axx, where:
A is a single alphabetic character called the format specifier. Any numeric format string that contains more than one alphabetic character, including white space, is interpreted as a custom numeric format string. For more information, see Custom Numeric Format Strings.
xx is an optional integer called the precision specifier. The precision specifier ranges from 0 to 99 and affects the number of digits in the result. Note that the precision specifier controls the number of digits in the string representation of a number. It does not round the number itself. To perform a rounding operation, use the Math.Ceiling, Math.Floor, or Math.Round method.
When precision specifier controls the number of fractional digits in the result string, the result strings reflect numbers that are rounded away from zero (that is, using MidpointRounding.AwayFromZero).
You should specify the formatting when you display the string.
What you need is to do the following, when you convert to string:
String.Format("{0:0.00}", formatedNumber);
Refer to This article for more details:

C# convert string to decimal 4dp

I need to take a string object and convert it to a decimal to 4 dp.
So for example:
string val = "145.83011";
decimal sss = Math.Round(Convert.ToDecimal(val), 4);
bring back 145.8301 - good
However:
string val = "145.8300";
decimal sss = Math.Round(Convert.ToDecimal(val), 4);
brings back 145.83
I need it to be 145.8300
I need it in a decimal format so can't use string format options.
Thanks
rob
One option would be to use string manipulation three times:
Parse the original text to a decimal value (this will preserve the original number of decimal places)
Use string formatting to end up with a string with exactly 4 decimal places. (Math.Round ensures there are at most 4DP, but not exactly 4DP.)
Parse the result of the formatting to get back to a decimal value with exactly 4DP.
So something like this:
public static decimal Force4DecimalPlaces(string input)
{
decimal parsed = decimal.Parse(input, CultureInfo.InvariantCulture);
string intermediate = parsed.ToString("0.0000", CultureInfo.InvariantCulture);
return decimal.Parse(intermediate, CultureInfo.InvariantCulture);
}
I recoil from using string conversions like this, but the alternatives are relatively tricky. You could either get the raw bits, split out the different parts to find the mantissa and scale, then adjust appropriately... or you could potentially work out some sequence of arithmetic operations to get to the right scale. (Jeppe's approach of multiplying by 1.0000m may well be entirely correct - I just don't know whether it's documented to be correct. It would at least be worth adding in appropriate tests for the sorts of numbers you expect to see.)
Note that the above code will perform round up on halves, as far as I can tell, so 1.12345 will be converted to 1.1235 for example.
Sample with output in comments:
using System;
using System.Globalization;
class Test
{
static void Main()
{
Console.WriteLine(Force4DecimalPlaces("0.0000001")); // 0.0000
Console.WriteLine(Force4DecimalPlaces("1.000000")); // 1.0000
Console.WriteLine(Force4DecimalPlaces("1.5")); // 1.5000
Console.WriteLine(Force4DecimalPlaces("1.56789")); // 1.5679
}
public static decimal Force4DecimalPlaces(string input)
{
decimal parsed = decimal.Parse(input, CultureInfo.InvariantCulture);
string intermediate = parsed.ToString("0.0000", CultureInfo.InvariantCulture);
return decimal.Parse(intermediate, CultureInfo.InvariantCulture);
}
}
Both Convert.ToDecimal and decimal.Parse do preserve trailing zeroes in the string (a System.Decimal can have at most 28-29 digits in total, so in most cases there's still room for all the trailing zeroes).
And Math.Round(..., 4) preserves trailing zeroes up to the fourth place after the decimal period.
Therefore the premise of the question is wrong. Your example does bring back what you want.
In any case, consider specifying the overload that takes in an IFormatProvider as well, and give CultureInfo.InvariantCulture as argument. Then the conversion is independent of the local culture.
If instead you want to handle strings like "145.83" and append trailing zeroes that were not in the string, use:
string val = "145.83";
decimal sss = Math.Round(
decimal.Parse(val, CultureInfo.InvariantCulture) * 1.0000m,
4);
Epilog: If you don't like multiplying and dividing by numbers like 1.0000m, use decimal.GetBits to get the internal representation. Adjust the integer "part" by multiplying or dividing by the appropriate power of ten, and adjust the scale "part" by subtracting or adding the corresponding number. The scale counts the number of places to move the decimal point to the left, starting from the 96-bit integer.

Double to string with mandatory decimal point

This is probably dumb but it's giving me a hard time. I need to convert/format a double to string with a mandatory decimal point.
1 => 1.0
0.2423423 => 0.2423423
0.1 => 0.1
1234 => 1234.0
Basically, I want to output all decimals but also make sure the rounded values have the redundant .0 too. I am sure there is a simple way to achieve this.
Use double.ToString("N1"):
double d1 = 1d;
double d2 = 0.2423423d;
double d3 = 0.1d;
double d4 = 1234d;
Console.WriteLine(d1.ToString("N1"));
Console.WriteLine(d2.ToString("N1"));
Console.WriteLine(d3.ToString("N1"));
Console.WriteLine(d4.ToString("N1"));
Demo
Standard Numeric Format Strings
The Numeric ("N") Format Specifier
Update
(1.234).ToString("N1") produces 1.2 and in addition to removing additional decimal digits, it also adds a thousands separator
Well, perhaps you need to implement a custom NumberFormatInfo object which you can derive from the current CultureInfo and use in double.ToString:
var culture = CultureInfo.CurrentCulture;
var customNfi = (NumberFormatInfo)culture.NumberFormat.Clone();
customNfi.NumberDecimalDigits = 1;
customNfi.NumberGroupSeparator = "";
Console.WriteLine(d1.ToString(customNfi));
Note that you need to clone it since it's readonly by default.
Demo
There is not a built in method to append a mandatory .0 to the end of whole numbers with the .ToString() method, as the existing formats will truncate or round based on the number of decimal places you specify.
My suggestion is to just roll your own implementation with an extension method
public static String ToDecmialString(this double source)
{
if ((source % 1) == 0)
return source.ToString("f1");
else
return source.ToString();
}
And the usage:
double d1 = 1;
double d2 = 0.2423423;
double d3 = 0.1;
double d4 = 1234;
Console.WriteLine(d1.ToDecimalString());
Console.WriteLine(d2.ToDecimalString());
Console.WriteLine(d3.ToDecimalString());
Console.WriteLine(d4.ToDecimalString());
Results in this output:
1.0
0.2423423
0.1
1234.0
You could do something like this: if the number doesn't have decimal points you can format its output to enforce one decimal 0 and if it has decimal places, just use ToString();
double a1 = 1;
double a2 = 0.2423423;
string result = string.Empty;
if(a1 - Math.Floor(a1) >0.0)
result = a1.ToString();
else
result = a1.ToString("F1");
if (a2 - Math.Floor(a2) > 0.0)
result = a2.ToString();
else
result = a2.ToString("F1");
When you use "F" as formatting, the output won't contain thousands separator and the number that follows it specifies the number of decimal places.
Use ToString("0.0###########################").
It does work. I found it in duplicate of your question decimal ToString formatting which gives at least 1 digit, no upper limit
Double provides a method ToString() where you can pass an IFormatProvider-object stating how you want your double to be converted.
Additionally, it should display trailing 0 at all costs.
value = 16034.125E21;
// Display value using the invariant culture.
Console.WriteLine(value.ToString(CultureInfo.InvariantCulture));
// Display value using the en-GB culture.
Console.WriteLine(value.ToString(CultureInfo.CreateSpecificCulture("en-GB")));
// Display value using the de-DE culture.
Console.WriteLine(value.ToString(CultureInfo.CreateSpecificCulture("de-DE")));
// This example displays the following output to the console:
// -16325.62015
// -16325.62015
// -16325,62015
// 1.6034125E+25
// 1.6034125E+25
// 1,6034125E+25
Here is the documentation from MSDN.
You can cast to string and then appen ".0" if there was no decimal point given
string sValue=doubleValue.ToString();
if(!sValue.Contains('.'))
sValue+=".0";
EDIT:
As mentioned in the comments '.' may not be the decimal seperator in the current culture. Refer to this article to retrieve the actual seperator if you want make your code save for this case.

Categories