3 回答

TA貢獻(xiàn)1874條經(jīng)驗(yàn) 獲得超12個(gè)贊
問(wèn)題是,.NET始終會(huì)在應(yīng)用格式之前四舍五入double為15位有效的十進(jìn)制數(shù)字,而不管您的格式要求的精度和二進(jìn)制數(shù)的確切十進(jìn)制值如何。
我猜想Visual Studio調(diào)試器有其自己的格式/顯示例程,這些例程直接訪問(wèn)內(nèi)部二進(jìn)制數(shù),因此C#代碼,C代碼和調(diào)試器之間存在差異。
沒(méi)有內(nèi)置的函數(shù)可以訪問(wèn)a的確切十進(jìn)制值double,也無(wú)法double將a 格式化為特定的小數(shù)位數(shù),但是您可以自己完成此工作,方法是將內(nèi)部二進(jìn)制數(shù)拆開并重建為十進(jìn)制值的字符串表示形式。
另外,您可以使用Jon Skeet的DoubleConverter類(從他的“二進(jìn)制浮點(diǎn)和.NET”文章鏈接到)。該ToExactString方法具有返回a的精確十進(jìn)制值的方法double。您可以輕松地對(duì)此進(jìn)行修改,以將輸出舍入為特定精度。
double i = 10 * 0.69;
Console.WriteLine(DoubleConverter.ToExactString(i));
Console.WriteLine(DoubleConverter.ToExactString(6.9 - i));
Console.WriteLine(DoubleConverter.ToExactString(6.9));
// 6.89999999999999946709294817992486059665679931640625
// 0.00000000000000088817841970012523233890533447265625
// 6.9000000000000003552713678800500929355621337890625

TA貢獻(xiàn)2003條經(jīng)驗(yàn) 獲得超2個(gè)贊
Digits after decimal point
// just two decimal places
String.Format("{0:0.00}", 123.4567); // "123.46"
String.Format("{0:0.00}", 123.4); // "123.40"
String.Format("{0:0.00}", 123.0); // "123.00"
// max. two decimal places
String.Format("{0:0.##}", 123.4567); // "123.46"
String.Format("{0:0.##}", 123.4); // "123.4"
String.Format("{0:0.##}", 123.0); // "123"
// at least two digits before decimal point
String.Format("{0:00.0}", 123.4567); // "123.5"
String.Format("{0:00.0}", 23.4567); // "23.5"
String.Format("{0:00.0}", 3.4567); // "03.5"
String.Format("{0:00.0}", -3.4567); // "-03.5"
Thousands separator
String.Format("{0:0,0.0}", 12345.67); // "12,345.7"
String.Format("{0:0,0}", 12345.67); // "12,346"
Zero
Following code shows how can be formatted a zero (of double type).
String.Format("{0:0.0}", 0.0); // "0.0"
String.Format("{0:0.#}", 0.0); // "0"
String.Format("{0:#.0}", 0.0); // ".0"
String.Format("{0:#.#}", 0.0); // ""
Align numbers with spaces
String.Format("{0,10:0.0}", 123.4567); // " 123.5"
String.Format("{0,-10:0.0}", 123.4567); // "123.5 "
String.Format("{0,10:0.0}", -123.4567); // " -123.5"
String.Format("{0,-10:0.0}", -123.4567); // "-123.5 "
Custom formatting for negative numbers and zero
String.Format("{0:0.00;minus 0.00;zero}", 123.4567); // "123.46"
String.Format("{0:0.00;minus 0.00;zero}", -123.4567); // "minus 123.46"
String.Format("{0:0.00;minus 0.00;zero}", 0.0); // "zero"
Some funny examples
String.Format("{0:my number is 0.0}", 12.3); // "my number is 12.3"
String.Format("{0:0aaa.bbb0}", 12.3);

TA貢獻(xiàn)1842條經(jīng)驗(yàn) 獲得超13個(gè)贊
盡管這個(gè)問(wèn)題已經(jīng)結(jié)束,但我認(rèn)為值得一提的是這種暴行是如何產(chǎn)生的。在某種程度上,您可能會(huì)指責(zé)C#規(guī)范,該規(guī)范指出雙精度數(shù)必須具有15或16位的精度(IEEE-754的結(jié)果)。進(jìn)一步(第4.1.6節(jié))指出,允許實(shí)現(xiàn)使用更高的精度。注意:更高,而不是更低。他們甚至允許從IEEE-754偏離:類型的表達(dá)式x * y / z,其中x * y將產(chǎn)生+/-INF,但將是一個(gè)有效的范圍分割后,不必導(dǎo)致錯(cuò)誤。此功能使編譯器更容易在可以產(chǎn)生更好性能的體系結(jié)構(gòu)中使用更高的精度。
但是我答應(yīng)了“理由”。這里有一個(gè)引號(hào)(您請(qǐng)求在你最近的評(píng)論一個(gè)資源)從共享源代碼CLI中clr/src/vm/comnumber.cpp:
“為了提供既便于顯示又可往返的數(shù)字,我們使用15位數(shù)字解析該數(shù)字,然后確定它是否往返為相同的值。如果是,則將NUMBER轉(zhuǎn)換為字符串,否則用17位數(shù)字重新解析并顯示出來(lái)?!?/p>
換句話說(shuō):MS的CLI開發(fā)團(tuán)隊(duì)決定既可以雙向訪問(wèn)又可以顯示漂亮的值,這些值并不難讀。是好是壞?我希望選擇加入或退出。
找出任何給定數(shù)字的這種往返性的技巧是什么?轉(zhuǎn)換為通用NUMBER結(jié)構(gòu)(對(duì)于double的屬性具有單獨(dú)的字段),然后再返回,然后比較結(jié)果是否不同。如果不同,則使用精確值(與中的值6.9 - i相同),如果相同,則使用“漂亮值”。
就像您在對(duì)Andyp的評(píng)論中提到的那樣,6.90...00等于6.89...9467?,F(xiàn)在您知道為什么0.0...8818使用它了:它與有所不同0.0。
這15位數(shù)字是硬編碼的,只能通過(guò)重新編譯CLI,使用Mono或調(diào)用Microsoft并說(shuō)服他們添加一個(gè)選項(xiàng)來(lái)打印完整的“精度”來(lái)更改(這不是真正的精度,但是由于缺少一個(gè)更好的詞)。自己計(jì)算52位精度或使用前面提到的庫(kù)可能會(huì)更容易。
編輯:如果您想用IEE-754浮點(diǎn)進(jìn)行實(shí)驗(yàn),請(qǐng)考慮使用此在線工具,該工具向您顯示浮點(diǎn)的所有相關(guān)部分。
- 3 回答
- 0 關(guān)注
- 416 瀏覽
添加回答
舉報(bào)