簡體   English   中英

將float轉換為double會失去精度C#

[英]Converting float to double loses precision C#

我有以下代碼

    double temp3 = 61.01;

    //This can actually be various other types, but float is the one that causes problems
    dynamic temp = 61.01f;
    double temp2 = (double)Convert.ChangeType(temp, typeof(double));

    double newValue = temp2 - temp3;

    //newValue should == 0 but it does not

    Console.WriteLine(String.Format("  {0:F20}", temp));
    Console.WriteLine(String.Format("  {0:F20}", temp2));
    Console.WriteLine(String.Format("  {0:F20}", temp3));
    Console.WriteLine(String.Format("  {0:F20}", newValue));

哪個產生

61.01000000000000000000

61.00999832153320000000

61.01000000000000000000

-0.00000167846679488548

為什么Convert.ChangeType失去精度?

我們使用Convert.ChangeType是因為使用了動態變量,該變量可以是byte / uint / float / double等

在此問題中觀察到的問題很大程度上是由Microsoft選擇格式引起的,尤其是Microsoft軟件無法顯示准確的值,因為即使格式字符串要求輸入更多的數字,它也會限制用於轉換為十進制的位數。 此外,轉換float時使用的位數少於轉換double時使用的位數。 因此,如果對具有相同值的floatdouble進行格式化,則結果可能會有所不同,因為float格式將使用較少的有效數字。

下面,我一步一步地研究問題中的代碼語句。 綜上所述,問題的關鍵是,值61.0099983215332被格式化為“61.0100000000000”,當它是一個float和“61.0099983215332”,當它是一個double 這純粹是Microsoft的格式選擇,並非由浮點運算的性質引起。

語句double temp3 = 61.01temp3初始化為正好61.00999999999999801048033987171947956085205078125。 由於二進制浮點格式的性質,必須從61.01開始進行此更改-它不能精確表示61.01,因此使用可表示為double的最接近值。

語句dynamic temp = 61.01ftemp精確地初始化為61.009998321533203125。 double ,已使用了最接近的可表示值,但是由於float精度較低,因此最接近的值不如double情況下那樣接近。

語句double temp2 = (double)Convert.ChangeType(temp, typeof(double)); temp轉換為與temp具有相同值的double ,因此其值為61.009998321533203125。

語句double newValue = temp2 - temp3; 正確地減去兩個值,得出准確的結果0.00000167846679488548033987171947956085205078125,沒有錯誤。

語句Console.WriteLine(String.Format(" {0:F20}", temp)); 格式化名為tempfloat 格式化float涉及對Single.ToString的Single.ToString 微軟的文檔有點含糊。 它說,默認情況下,僅返回七(十進制)個精度數字。 它說使用GR格式最多獲取9個,而F20既不使用G也不使用R 因此,我相信只使用了七個數字。 當61.009998321533203125四舍五入到七個有效十進制數字時,結果為“ 61.01000”。 然后, ToString方法將此值填充到小數點后的20位,從而產生“ 61.01000000000000000000”。

接下來,我將介紹您的第三條WriteLine語句,然后再返回第二條。

語句Console.WriteLine(String.Format(" {0:F20}", temp3)); 格式化名為temp3double temp3 由於temp3double ,因此將調用Double.ToString 此方法使用15位精度(除非使用GR )。 將61.00999999999999801048033987171947956085205078125舍入為15個有效十進制數字時,結果為“ 61.0100000000000”。 然后, ToString方法將此值填充到小數點后的20位,從而產生“ 61.01000000000000000000”。

語句Console.WriteLine(String.Format(" {0:F20}", temp2)); 格式化名為temp2double temp2 temp2是一個double值,其中包含float temp中的值,因此它包含61.009998321533203125。 將其轉換為15個有效十進制數字時,結果為“ 61.0099983215332”。 然后, ToString方法將此值填充到小數點后的20位,從而產生“ 61.00999832153320320000000”。

最后,語句Console.WriteLine(String.Format(" {0:F20}", newValue)); 格式化newValue 將.00000167846679488548033987171947956085205078125格式化為15個有效數字會產生“ 0.00000167846679488548”。

這是因為浮點數分配給它們的位數少於雙精度數。 浮點數通常有23位,而雙精度數通常有52位。因此,通過轉換,您基本上是在砍掉位,直到可以將其放入浮點數為止。 因此,這就是您降低精度的原因。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM