簡體   English   中英

在C和Objective C中,我們幾乎不應該只使用(int)將float或double值轉換為整數嗎?

[英]In C and Objective C, should we almost never cast a float or double value to integer just using (int)?

我剛剛遇到Objective-C中的情況,其中:

NSLog(@"%i", (int) (0.2 * 10));         // prints 2
NSLog(@"%i", (int) ((1.2 - 1) * 10));   // prints 1

所以我想知道,如果值是float或double,並且我們想要一個整數,我們是否應該只使用(int)來進行轉換,但是使用(int) round(someValue) 或者,為了解決問題,我們何時應該使用(int) ,但在這些情況下,不能(int) round(someValue)也能完成這項工作,所以我們幾乎總是使用(int) round(someValue)

這里的問題不是將浮點值轉換為整數,而是將浮點數發生的舍入錯誤。 當你使用浮點數時,你應該理解它。

float和double的常見實現使用IEEE 754二進制浮點值。 這些值表示為有效數乘以2的冪乘以符號(+1或-1)。 對於浮點數,有效數字是24位二進制數字,在“小數點”之前有一位(或者如果您願意,則為“二進制點”)。 例如,數字1.25的有效位數為1.01000000000000000000000。 對於雙精度,有效數字是一個53位二進制數字,在該點之前有一位。

因此,無法准確表示十進制數字.1和1.1的值。 它們必須近似。 當您在源代碼中編寫“.1”或“1.1”時,編譯器會將其轉換為非常接近實際值的double。 有時,結果會略大於實際值。 有時它會略低於實際值。

將float轉換為int時,結果(根據定義)僅為值的整數部分(該值被截斷為零)。 因此,如果您的值略大於正整數,則獲得整數。 如果您的值略小於正整數,則會得到下一個較低的整數。

如果你期望精確的數學會給你一個整數結果,並且你正在執行的浮點運算是如此簡單以至於錯誤沒有累積太多,那么你可以將浮點值舍入為整數,使用圓函數。 在簡單的情況下,你也可以通過在截斷之前添加.5來舍入,如通過寫“(int)(f + .5)”。

這取決於你想要什么。 顯然,直接轉換為int將比調用round更快,而round將提供更准確的值。

除非你正在做的是依賴於速度的代碼是有效的(在這種情況下,浮點值可能不是最好用,要么),我會說,這是值得的叫round 即使它只改變你在屏幕上顯示一個像素的東西,在處理某些事物(角度測量,顏色等)時,你可以獲得更好的准確性。

編輯:簡單的測試來支持我的鑄造聲稱比舍入更快:

在Macbook Pro上測試:

  • 2.8 GHz Intel Core 2 Duo
  • Mac OS 10.7.4
  • Apple LLVM 3.1編譯器
  • -O0(無優化)

碼:

int value;
void test_cast()
{
    clock_t start = clock();
    value = 0;
    for (int i = 0; i < 1000 * 1000; i++)
    {
        value += (int) (((i / 1000.0) - 1.0) * 10.0);
    }

    printf("test_cast: %lu\n", clock() - start);
}

void test_round()
{
    clock_t start = clock();
    value = 0;
    for (int i = 0; i < 1000 * 1000; i++)
    {
        value += round(((i / 1000.0) - 1.0) * 10.0);
    }

    printf("test_round: %lu\n", clock() - start);
}

int main()
{
    test_cast();
    test_round();
}

結果:

test_cast: 11895
test_round: 14353

注意:我知道clock()不是最好的分析功能,但它確實表明round()至少使用了更多的CPU周期。

轉換為int將float或double值舍入為零。

1.1 - > 1,1.99999999999 - > 1,2.0 - > 2

-1.1 - > -1,-1.999999999 - > -1,-2 - > -2

那是你要的嗎? 如果是,那就是你應該做的。 如果沒有,你想要什么?

浮點算法總是會產生舍入誤差。 因此,例如0.2 * 10將給出接近2的數字。可能會少一點,或者稍微多一點,或者純粹的機會它可能正好是2.因此(int)(0.2 * 10)可能是1或2,因為“略小於2”將轉換為1。

round(x)將舍入到最接近的整數。 再次,如果你計算round(1.4 + 0.1),1.4和0.1之和是一個非常接近1.5的數字,可能會少一點,也許更多,所以你不知道它是否被舍入到1.0或2.0 。

您是否希望將1.5到2.5之間的所有數字四舍五入為2? 使用(int)round(x)。 如果x為1.5或2.5,則結果可能略有不同。 也許你希望數字高達1.9999向下舍入,但1.99999999四舍五入為2.使用double,而不是float,並計算(int)(x + 0.000001)。

暫無
暫無

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

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