Strange string.Format behavior - c#

I've a double variable called totalCost and it's value is 1025.
The result of calling a simple string.Format is the following:
?string.Format("{0}",totalCost)
"1,025"
My thousand separator is the dot while the decimal separator is the coma.
The weird part is the following:
?string.Format("{0:0.0}",totalCost)
"1,0"
Doesn't it should be 1025.0 (or 1,025.0)?
It seems that it converts the double in a string (giving "1.025") and then re-parse it without using my separator settings (interpreting it as 1-and-25-thousandths) and finally it formats the converted value.
EDIT: the thread culture is:
?System.Threading.Thread.CurrentThread.CurrentCulture
{it-IT}

You scenario is not what you think it is. I am 100% sure that your real value of totalCost is actually 1.025 (one and twenty five thousandths), because this is the only value that will produce both the same results that you have given.
This can be seen with the following code:
double d = 1.025;
Console.WriteLine(string.Format(new System.Globalization.CultureInfo("it-IT"), "{0}",d));
//1,025
Console.WriteLine(string.Format(new System.Globalization.CultureInfo("it-IT"), "{0:0.0}",d));
//1,0
As you can see, both outputs match with yours. I would suggest you use a debugger to step through the code and see at which point the value is being changed. (perhaps you are dividing by 1000 somewhere along the line)
Direct Answer: There is no strange behaviour, the code is working exactly as expected.

Related

Locale/Culture problems converting string to decimal

I have a simple string received via a parameter:
"1.00"
Based on locale of visitor it sometimes converts to:
"1" or "1,00"
The second one is a problem, I always need it to be a period (dots). $,£
I am using:
decimal price = Convert.ToDecimal(stringPrice, new CultureInfo("en-GB"));
Why is it still converting to "1,00" decimal if I use en-GB culture? I tried InvariantCulture, and the same thing happens. Why is this happening? It shouldn't matter because it's on the back end, right?
The conversion is going fine - internally, you get a decimal representation of 1.00 in your variable (price). Whether you see "1,00" or something else depends on where you are outputting the variable. Please look at how you are printing it, to see how it should display.

Rounding decimal number upto two decimal places

I am trying to round decimal number upto two decimal places which is working perfectly.
I am doing as below :
Math.Round(Amount, 2)
So, if I have Amount as 40000.4567, I am getting 40000.46which is exactly what I want.
Now problem is I have decimal number like 40000.0000, when I round it, the result is 40000, and what I really want is 40000.00. So round will always neglect trailing zeros.
To solve this problem, I have the option of converting it to string and use format , but I don't want to do that as that will be inefficient and I believe there must be some way to do it better.
I also tried something like
Decimal.Round(Amount, 2)
Now one way can be to check whether number contains anything in fractional part and use round function accordingly , but that is really bad way to do it.
I can't use truncate as well due to obvious reasons of this being related to amount.
What is the way around?
It is rounding correctly but you fail to understand that the value is not the format. There is no difference between the two values, 40000 and 40000.00, and you'll have a similar issue with something like 3.1.
Simply use formatting to output whatever number you have to two decimal places, such as with:
Console.WriteLine(String.Format("{0:0.00}", value));
or:
Console.WriteLine(value.ToString("0.00"));
You are mixing two things - rounding and output formatting. In order to output a number in a format you want you can use function string.Format with required format, for example:
decimal number = 1234.567m;
string.Format("{0:#.00}", number);
You can read more about custom numeric format strings in MSDN
I think what you're looking for is displaying two decimals, even if they are zero. You can use string.Format for this (I've also combined it with Round):
Console.WriteLine(string.Format("{0:0.00}", Math.Round(Amount, 2));
for rounding decimal number you can use
decimal number=200.5555m;
number= Math.Round(number, 2);
string numString= string.Format("{0:0.00}", number);

Does ToString("F") lose precision relative to ToString("G")?

I'm programming in C# using .Net 3.5, trying to control the format in which floats are output as strings.
However, I'm seeing some unexpected behaviour. If my code contains (for example):
float value = 50.8836975;
Edit Sorry, that (deleted) code "sample" was unhelpful. Basically, my question was seeking to explain the results of my debugging statements below when I set a breakpoint after "value" - a C# float - had been assigned the result of a calculation. Jon Skeet's answer is exactly what I needed (his first line takes me to task for the unhelpful code).
Then I see the following results when I try various options in my Immediate window:
?value
50.8836975
?value.ToString("G9")
"50.8836975"
?value.ToString("F9")
"50.883700000"
Can anyone explain why my F9-formatted value seems to have lost 3 digits of precision?
Your question is unclear because you've given a real value without an f suffix, and tried to assign it to a float variable. If you're actually using a float variable, then the exact value is
50.883697509765625
If you're actually using a double variable, then the exact value is:
50.8836974999999966939867590554058551788330078125
I get the same results as you for F9 if you use a float, but not if you use a double.
The reason for the reduced precision is revealed by the documentation for System.Single (float):
By default, a Single value contains only 7 decimal digits of precision, although a maximum of 9 digits is maintained internally.
I believe F is correctly displaying all of the real digits of precision, in an attempt to prevent you from believing that you've actually got more information than you have.

Float to String format specifier

I have some float values I want to convert to a string, I want to keep the formatting the same when converting, i.e. 999.0000(float) -> 999.0000(String). My problem is when the values contain an arbitrary number of zeroes after the decimal point, as in the previous example, they are stripped away when converting to a string, so the result I actually end up with is 999.
I looked at the format specifiers for the toString() method on MSDN, the RoundTrip ('R') specifier looks like it will produce what I want, but it is only supported for Single, Double and BigInt variables. Is there a format specifier like this for float variables?? Or would it be easier to just convert the values to doubles?
UPDATE: Just for clarity, the reason why I want to keep the trailing zeroes is because I'm doing a comparison of decimal places, i.e. I'm comparing the number of digits after the decimal place between two values. So for example, 1.00 and 1.00000 have a different number of digits after the decimal point. I know it's a strange request, it's for work and the requirement is coming from on high.
UPDATE 2-3-11:
I was thinking about this too hard, I'm reading the numbers from a txt file and then parsing them as floats, I'm going to modify the program to check whether the string values are decimals or whole numbers. Sorry for wasting your time, although this was very insightful.
Use ToString() with this format:
12345.678901.ToString("0.0000"); // outputs 12345.6789
12345.0.ToString("0.0000"); // outputs 12345.0000
Put as much zero as necessary at the end of the format.
Firstly, as Etienne says, float in C# is Single. It is just the C# keyword for that data type.
So you can definitely do this:
float f = 13.5f;
string s = f.ToString("R");
Secondly, you have referred a couple of times to the number's "format"; numbers don't have formats, they only have values. Strings have formats. Which makes me wonder: what is this thing you have that has a format but is not a string? The closest thing I can think of would be decimal, which does maintain its own precision; however, calling simply decimal.ToString should have the effect you want in that case.
How about including some example code so we can see exactly what you're doing, and why it isn't achieving what you want?
You can pass a format string to the ToString method, like so:
ToString("N4"); // 4 decimal points Number
If you want to see more modifiers, take a look at MSDN - Standard Numeric Format Strings
In C#, float is an alias for System.Single (a bit like intis an alias for System.Int32).

Floating Point Number parsing: Is there a Catch All algorithm?

One of the fun parts of multi-cultural programming is number formats.
Americans use 10,000.50
Germans use 10.000,50
French use 10 000,50
My first approach would be to take the string, parse it backwards until I encounter a separator and use this as my decimal separator. There is an obvious flaw with that: 10.000 would be interpreted as 10.
Another approach: if the string contains 2 different non-numeric characters, use the last one as the decimal separator and discard the others. If I only have one, check if it occurs more than once and discards it if it does. If it only appears once, check if it has 3 digits after it. If yes, discard it, otherwise, use it as decimal separator.
The obvious "best solution" would be to detect the User's culture or Browser, but that does not work if you have a Frenchman using an en-US Windows/Browser.
Does the .net Framework contain some mythical black magic floating point parser that is better than Double.(Try)Parse() in trying to auto-detect the number format?
I think the best you can do in this case is to take their input and then show them what you think they meant. If they disagree, show them the format you're expecting and get them to enter it again.
I don't know the ASP.NET side of the problem but .NET has a pretty powerful class: System.Globalization.CultureInfo. You can use the following code to parse a string containing a double value:
double d = double.Parse("100.20", CultureInfo.CurrentCulture);
// -- OR --
double d = double.Parse("100.20", CultureInfo.CurrentUICulture);
If ASP.NET somehow (i.e. using HTTP Request headers) passes current user's CultureInfo to either CultureInfo.CurrentCulture or CultureInfo.CurrentUICulture, these will work fine.
You can't please everyone. If I enter ten as 10.000, and someone enters ten thousand as 10.000, you cannot handle that without some knowledge of the culture of the input. Detect the culture somehow (browser, system setting - what is the use case? ASP? Internal app, or open to the world?), or provide an example of the expected formatting, and use the most lenient parser you can. Probably something like:
double d = Double.Parse("5,000.00", NumberStyles.Any, CultureInfo.InvariantCulture);
The difference between 12.345 in French and English is a factor of 1000. If you supply an expected range where max < 1000*min, you can easily guess.
Take for example the height of a person (including babies and children) in mm.
By using a range of 200-3000, an input of 1.800 or 1,800 can unambiguously be interpreted as 1 meter and 80 centimeters, whereas an input of 912.300 or 912,300 can unambiguously be interpreted as 91 centimeters and 2.3 millimeters.

Categories