2012-01-11 48 views
0
#include "string.h" 
#include "math.h" 

int main() 
{ 
    double result = (double)sqrt(2.3456F); 
    unsigned char data[8]; //holds the bytes of the result 

    memmove(data,&result,8); 
    for(int i=0;i<8;i++) 
     printf("%d\n",data[i]); 
    return 0; 
} 

上述相同的代碼將sqrt()結果轉換爲double,然後存儲在另一個雙變量中。這裏的數據保存了浮點數結果的二進制表示。在Visual C++ 6.0和Visual C++ 2010上運行時,相同的代碼給出了不同的結果。這是爲什麼?Visual Studio版本中的數學函數的問題

還有一件事是如果結果是浮點數,那麼Visual C++ 6.0和Visual C++ 2010會給出相同的結果值。

任何機構都可以解決這個問題嗎?

輸出與結果變量爲雙::

與結果可變數據::

[0] 196 'Ä' 
[1] 12 '' 
[2] 25 '' 
[3] 254 'þ' 
[4] 42 '*' 
[5] 129 '' 
[6] 248 'ø' 
[7] 63 '?' 

用Visual C++ 2010

數據的Visual C++ 6.0

字節表示: :

[0] 0 unsigned char 
    [1] 0 unsigned char 
    [2] 0 unsigned char 
    [3] 0 unsigned char 
    [4] 43 '+' unsigned char 
    [5] 129 '' unsigned char 
    [6] 248 'ø' unsigned char 
    [7] 63 '?' unsigned char 

輸出與結果變量被浮子::

用Visual C++ 6.0

[0] 88 'X' 
    [1] 9 ' ' 
    [2] 196 'Ä' 
    [3] 63 '?' 

用Visual C++ 2010

我得到如以上對結果變量相同的二進制值。

+1

這看起來像'C',不'C的精度版本++ '? – 2012-01-11 09:19:49

+2

@Paul R:這仍然是有效的C++和編寫'int main()'在C++中比在C中更習慣於寫入'int main(void)'。 – Benoit 2012-01-11 09:23:46

+0

你應該使用printf(「%hhu」)'來打印[unsigned chars](http://en.cppreference.com/w/cpp/io/c/fprintf)。 – Benoit 2012-01-11 09:26:24

回答

3

那麼,這兩個double值幾乎是一樣的。 首先,您應該瞭解實數是如何在內存中表示的:http://en.wikipedia.org/wiki/Double-precision_floating-point_format

您可以看到,數據的第一個字節表示不同,只是最小的一小部分。現在,讓我們做一個實驗和研究,什麼樣的價值觀,我們得到了兩個數字:一個來自sqrt計算,第二替換前4個字節爲0讓打印出雙數字結果,分數和字節represenation

void show(double result) 
{ 
    unsigned char * data = (unsigned char*)&result; 
    unsigned long long fraction = *(unsigned long long int*)&result; 

    fraction = fraction & 0xFFFFFFFFFFFFF;//52-bit mask! 
    printf("result: %8f, with fraction %4lld. ", result, fraction); 
    for(int i=0;i<8;i++) 
     printf("%2X ",data[i]); 
    printf("\n"); 
} 

int main() 
{ 
    double result = (double)sqrt(2.3456F); 
    show(result); 
    unsigned char * data = (unsigned char*)&result; 
    memset(data, 0, 4); 
    show(result); 
    return 0; 
} 

對於我的輸出是

result: 1.531535, with fraction 2393821627440998. 66 5F C2 7 2B 81 F8 3F 
result: 1.531535, with fraction 2393821497262080. 0 0 0 0 2B 81 F8 3F 

如我們所見,結果在兩種情況下都是相同的。事情是,當指數如此大的值時,其最小有效位的變化不會產生整數的實際變化。

好的,爲什麼這些值不同,而他們是相同的計算結果?這是因爲編譯器。不同的編譯器生成的代碼略有不同,產生的結果稍有不同。但是,你應該考慮這些2個值相同

編輯:這樣的行爲 嘛確切的結果,你原來有一個float號碼,讓你的23位精度。您對該值計算了sqrt,並得到仍具有23位精度的float值。比你把它轉換成雙精度,精度爲52位。所以,你試圖擴展精度,但是你沒有足夠的信息來正確地做到這一點,這就是爲什麼你完成double,仍然有float精度。而且所有比特都不重要,第23個得到隨機值。如果您有

sqrt(2.3456) 

更換

(double)sqrt(2.3456F) 

你會得到相同的結果有兩種編譯器,因爲您將使用double - 開方

+0

感謝您的答覆。在這裏我使用的是相同的Visual C++編譯器,但版本不同。我不認爲版本升級會導致這個問題。 – Mahesh 2012-01-11 10:33:25

+0

這不是問題。這只是正常的行爲。實數不代表_exactly_。你必須忍受這一點。你可以看到我的'gcc'默認生成了第三個表示,而不是你提到的兩個中的一個 – Lol4t0 2012-01-11 10:36:06

+0

我的意圖是我重新實現了Visual C++ 2010中已經存在的代碼,但是結果並不匹配由於這個問題,因爲代碼涉及諸如指數運算這樣的諸多運算,所以有可能使它們完全相同。 – Mahesh 2012-01-11 11:44:09