StringBuilder.Append with a float

StringBuilder.Append , using float , truncates the value. What is a transformation and how can I stop it from truncating?

AttributeOrder is a float type, and I lose accuracy when building the string.

 if ( AttributeOrder != 0 ) { if ( Result.Length > 0 ) { Result.Append( " AND " ); } Result.Append( COLUMN_ATTRIBUTE_ORDER ); Result.Append( "=" ); Result.Append( AttributeOrder ); } 

EDIT: This is legacy code, I cannot change the underlying data types. The SQL Server column is real, and the data type is float . I need to present the float as it is being filled, as a string for other purposes and not lose accuracy as it is.

+4
source share
5 answers

You can convert float to string using string , for example:

 Result.Append(AttributeOrder.ToString("G9")) 

Or alternatively

 Result.AppendFormat("{0}={1:G9}", COLUMN_ATTRIBUTE_ORDER, AttributeOrder) 

However, you cannot get more than 9 digits of precision from the float , and the numbers 8 and 9 will be inaccurate.


float datatype can only contain seven digits of precision. Once you put the value in the variable float , you will not lose accuracy. To save all 24 digits of precision with SQL Server, you need to use the decimal data type .

Once you change the variable to decimal , Append will provide you with as many digits as you put.

+4
source

If you need to provide a representation of a floating point number, you must use System.Decimal - System.Single , cannot accurately represent the precision you want to display.

This simple example shows the difference:

 using System; class Test { static void Main() { Single s = 1.23456789f; Decimal d = 1.23456789m; Console.WriteLine(s); Console.WriteLine(d); } } 
+2
source

Let's have some fun with floats and see why this doesn't work.

Let's say that the 24-digit number 1.23456789012345678901234 is read from SQL real in .Net float .

The float value looks like binary: 0 01111111 00111100000011001010010

The first 0 is a signed bit indicating that the number is positive. 01111111 is a biased indicator indicating that the value is multiplied by 2 ^ 0 (or 1). 00111100000011001010010 - digits of the number, minus the first bit.

So, the float variable now encodes the number 1.00111100000011001010010 in binary format.

Let's see what happens when we convert this float to decimal.

 1 * 1 = 1 . 0 * 0.5 = 0 0 * 0.25 = 0 1 * 0.125 = 0.125 1 * 0.0625 = 0.0625 1 * 0.03125 = 0.03125 1 * 0.015625 = 0.015625 0 * 0.0078125 = 0 0 * 0.00390625 = 0 0 * 0.001953125 = 0 0 * 0.0009765625 = 0 0 * 0.00048828125 = 0 0 * 0.000244140625 = 0 1 * 0.0001220703125 = 0.0001220703125 1 * 0.00006103515625 = 0.00006103515625 0 * 0.000030517578125 = 0 0 * 0.0000152587890625 = 0 1 * 0.00000762939453125 = 0.00000762939453125 0 * 0.000003814697265625 = 0 1 * 0.0000019073486328125 = 0.0000019073486328125 0 * 0.00000095367431640625 = 0 0 * 0.000000476837158203125 = 0 1 * 0.0000002384185791015625 = 0.0000002384185791015625 0 * 0.00000011920928955078125 = 0 ------------------------ 1.2345678806304931640625 

So, if we display all the digits of the floating point number, we get 1.2345678806304931640625. Isn't that the number we want to display? Why does he round this number? And why is this value different from the number we started with?

To understand why, go through some adjacent floating point values:

 binary floating point representation decimal representation ------------------------------------ ---------------------- 0 01111111 00111100000011001010000 = 1.2345676422119140625 0 01111111 00111100000011001010001 = 1.23456776142120361328125 0 01111111 00111100000011001010010 = 1.2345678806304931640625 0 01111111 00111100000011001010011 = 1.23456799983978271484375 0 01111111 00111100000011001010100 = 1.234568119049072265625 

As you can see, the exact same floating-point number is used to represent all the values ​​in this range: [1.234567821025848388671875, 1.234567940235137939453125)

Therefore, any decimal digits after the eighth are lost during conversion to a float, and any that can be displayed are completely meaningless and are not related to the actual value that is presented.

All decimal digits after the eighth are an artifact of rounding to a 24-bit binary and converting to decimal, and they have no actual value.

+2
source

You can always use the ToString() method for your float, for example:

 if ( AttributeOrder != 0 ) { if ( Result.Length > 0 ) { Result.Append( " AND " ); } Result.Append( COLUMN_ATTRIBUTE_ORDER ); Result.Append( "=" ); Result.Append( AttributeOrder.ToString("0.000000") ); } 

For example, the format specifier above contains 6 decimal places. Replace 0 with # if you do not want to display trailing zeros.

0
source

You can kill several birds with string.Format() . Reduce the lines of code and show the number of arbitrary precision.

 Result.Append(string.Format("{0}={1:0.000000}", COLUMN_ATTRIBUTE_ORDER, AttributeOrder)); 
0
source

All Articles