2011-11-09 128 views
7

我在維基百科(http://en.wikipedia.org/wiki/Type_conversion#Implicit_type_conversion)上偶然發現了下面的例子。C中的隱式類型轉換

#include <stdio.h> 

int main() 
{ 
    int i_value = 16777217; 
    float f_value = 16777217.0; 
    printf("The integer is: %i\n", i_value); // 16777217 
    printf("The float is: %f\n", f_value); // 16777216.000000 
    printf("Their equality: %i\n", i_value == f_value); // result is 0 
} 

他們的解釋:「這奇數行爲是由i_value的隱式轉換引起的浮起當它與f_value比較;被比較,其損失精度,使得值的鑄造不同」

這不正確嗎?如果i_value被轉換爲浮點數,那麼兩者在精度上會有相同的損失,並且它們會相等。 所以i_value必須轉換成雙倍。

+0

使用g ++(GCC 4.6.2)我得到'1'的等式。 –

+0

@Kerrek:和我。在VS中,我得到0. –

+0

@OliCharlesworth:我很好奇將字面值改爲f或將類型改爲double值 - 在所有情況下我都得到了'1' ... –

回答

7

否,在平等操作者的情況下,「通常的算術轉換」發生,這開始:

  • 首先,如果對應的實數型有一個操作數的是long double,所述其他操作數將被轉換,而不會將類型爲 的域更改爲對應的實際類型爲long double的類型。否則,如果任一操作數的對應實型爲double,則另一個操作數將被轉換,而不會更改類型爲 域的類型,其類型對應的實型爲double
  • 否則,如果對應的真實類型有一個操作數的是float,則另一個操作數轉換,而不 型結構域的變化,以一類型,其相應的實際類型是float

最後一種情況適用於這裏:i_value轉化爲float

,你可以從比較看到一個奇怪的結果,儘管這樣做的原因,是因爲這個警告通常的算術轉換:

浮動操作數的值浮動的結果,並表達式可以以比該類型所需的 更高的精度和範圍表示;類型不會因此而改變。

這是正在發生的事情:轉換後的i_value的類型仍然是float,但在此表達你的編譯器正在利用這個緯度和代表它在更高的精度比float。編譯387兼容浮點時,這是典型的編譯器行爲,因爲編譯器會在浮點堆棧上留下臨時值,浮點堆棧以80位擴展精度格式存儲浮點數。

如果您的編譯器爲gcc,則可以通過給出-ffloat-store命令行選項來禁用此附加精度。

+0

在x64上,gcc使用顯式cvtsi2ssl指令將整數轉換爲浮點型。然而,在x86上,這正是發生的事情,實際上更高的精度甚至超過了兩倍。 –

+0

@ konrad.kruczynski:是的,你可以通過提供'-mfpmath = sse'選項(這也需要'-msse'或者一個暗示這個選項的選項)來在x86上得到相同的結果。 – caf

-1

我相信32位IEEE浮點可以容納的最大整數值是1048576,它比上面的數字要小。所以,浮點數值不會完全對應16777217.

我不確定的部分是編譯器如何比較兩種不同類型的數字(即float和int) 。我能想到的三種不同的方式,這可能做到:

1)轉換兩個值「浮動」(這應該使這些值是相同的,所以這可能是不是編譯器做什麼)

2)將這兩個值轉換爲「int」(這可能會或可能不會顯示它們相同...轉換爲經常截斷的int,因此如果浮點值爲16777216.99999,則轉換爲「int」將截斷)

3)將這兩個值轉換爲「double」。我的猜測是這是編譯器會做的。如果這是編譯器所做的,那麼這兩個值肯定會不同。 double可以精確地保存16777217,它也可以精確地表示16777217.0轉換爲的浮點值(不完全是16777217.0)。

+3

1048576是2^20,所以這是不正確的。 –

0

這裏有一些很好的答案。您必須非常小心地在各種整數和各種浮點表示之間進行轉換。

我通常不會測試相等的浮點數,特別是如果其中一個來自整數類型的隱式或顯式轉換。我在一個充滿幾何計算的應用程序上工作。儘可能地,我們使用規範化整數(通過強制輸入數據中我們將接受的最大精度)。對於必須使用浮點的情況,如果需要比較,我們將對差值應用絕對值。