1

I would like to understand what is going on with this code:

float flt = 0.123F; string s1 = flt.ToString("0.#########"); // "0.123" string s2 = flt.ToString("N9"); // "0.123000003" 

where the value of flt in the debugger is 0.123:

enter image description here

The documentation on the "#" custom numeric format specifier states:

If the value that is being formatted has a digit in the position where the "#" symbol appears in the format string, that digit is copied to the result string. Otherwise, nothing is stored in that position in the result string.

The documentation on the standard numeric format with precision specifier doesn't explain why it adds the 000003 at the end.

  1. Why aren't these two formats equivalent?
  2. Why does the "standard" format add 000003 to the end of the variable that only has 0.123?

2 Answers 2

4

TL:DR;

I'd point it back to two things:

  1. Custom formats not returning more digits than they can be sure of being correct due to legacy reasons.
  2. Floating point inaccuracies within the Dragon4 algorithm that is used when generating the string for the Numeric format specifier (N). Which is to be expected as there is no way to be more accurate with the given precision of a float! So this is not necessarily related to the algorithm used.

Issue fixes itself using decimals:

decimal dec = 0.123M; string s1 = dec.ToString("0.#########"); // "0.123" string s2 = dec.ToString("N9"); // "0.123000000" 

In depth

Using the ### syntax the formatter won't allow you to print any more decimal digits than it is sure that are correct. Lets test this by trying a few samples:

Lets try with more decimal digits. Note that the Numeric format specifier lets us print more characters:

float flt = 1f/3f; flt.ToString("0.#########").Dump(); // 0.3333333 flt.ToString("N9").Dump(); // 0.333333343 

We get more characters when using a more precise data type, but still a character limit using the #.

double dbl = 1D/3D; dbl.ToString("0.#################").Dump(); // 0,333333333333333 dbl.ToString("N17").Dump(); // 0,33333333333333331 

We can track it back to this. Which gets the precision from TNumber.MaxPrecisionCustomFormat with its documentation:

SinglePrecisionCustomFormat and DoublePrecisionCustomFormat are used to ensure that custom format strings return the same string as in previous releases when the format would return x digits or less (where x is the value of the corresponding constant). In order to support more digits, we would need to update ParseFormatSpecifier to pre-parse the format and determine exactly how many digits are being requested and whether they represent "significant digits" or "digits after the decimal point".

Concrete Answers

Why aren't these two formats equivalent?

Due to legacy reasons, as the custom format will only show "known" digits. And the Numeric format will show you all requested digits, even though they might be inaccurate.

Why does the "standard" format add 000003 to the end of the variable that only has 0.123?

The numeric format adds "000003" to the end of the variable, because you asked it to do so. You asked for 9 decimal digits, you got 9 decimal digits even if they might not be correct.

The custom format won't add any digits to the end of the decimal digits, as between the 3rd and the 7th decimal digit (In your sample you added 9 # though the last 2 get ignored), there are only 0s and the custom format ignores any ending 0s as stated here.

Note that this specifier never displays a zero that is not a significant digit, even if zero is the only digit in the string. It will display zero only if it is a significant digit in the number that is being displayed.

Sign up to request clarification or add additional context in comments.

Comments

0

Floating point numbers do not store an exact value. Visiting the IEEE floating point converter here, you'll discover that the value 0.123F is actually stored as 0.123000003397464752197265625.

Floating point is a method for storing approximate values in a binary format. .NET supports both single-precision and double-precision floating point numbers. The double-precision format takes double the storage space of the single-precision format, and it's still storing approximate values.

Floating point format for 0.123F

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.