2011-02-25 70 views
15

平方根的3中,作爲估計由鎢阿爾法:爲什麼gdb將sqrt(3)評估爲0?

1.7320508075688772935274463415058723669428052538103806280558... 

當我用C做sqrt(3),它的計算結果爲0。爲什麼呢?

EDIT4:以下介紹如何在GDB中重現此問題。創建test.c如下:

#include <stdio.h>                                          
#include <math.h> 

int main() 
{ 
    printf("sqrt(3): %f\n", sqrt(3)); 
    return 0; 
} 

編譯:

gcc -O0 -g -Wall -pedantic -ansi -lm -o test test.c 

運行調試器:

gdb test 

在控制檯輸入以下內容:

(gdb) break test.c:6 
Breakpoint 1 at 0x400578: file test.c, line 6. 
(gdb) r 
Starting program: /home/pdedecker/Desktop/test 
Breakpoint 1, main() at test.c:6 
6   printf("sqrt(3): %f\n", sqrt(3)); 
(gdb) print sqrt(3) 
$1 = 0 
(gdb) s 
sqrt(3): 1.732051 

我的GDB版本爲GNU gdb (GDB) SUSE (7.1-3.12)

+10

向我們展示您用來獲取此結果的代碼。 – birryree 2011-02-25 20:59:44

+6

您是否包含''? – 2011-02-25 21:02:02

+0

+1 Jeremiah,我記得我也面對那個錯誤的老年人:) – 2011-02-25 21:03:04

回答

16

的問題不是缺少函數聲明(這ISN不要錯過,因爲你確實包括了<math.h>)。

的問題是缺少對sqrt你實際使用的是調試信息。如果沒有這些調試信息,GDB不知道要傳遞給sqrt()的參數類型以及返回的內容。

您可以通過安裝的libc-debuginfo軟包得到很多Linux發行版所需要的調試信息。以下是我看到這樣一個系統:

gdb -q ./a.out 
Reading symbols from /tmp/a.out...done. 
(gdb) b main 
Breakpoint 1 at 0x400558: file t.c, line 6. 
(gdb) r 

Breakpoint 1, main() at t.c:6 
6  printf("sqrt(3): %f\n", sqrt(3)); 
(gdb) p sqrt 
$1 = {<text variable, no debug info>} 0x7ffff7b7fb50 <__sqrt> 

注: 「沒有調試信息」

(gdb) p sqrt(3) 
$2 = 0 
(gdb) p sqrt(3.0) 
$3 = 0 

注意:符合你的行爲。 什麼sqrt函數有調試信息?

(gdb) info func sqrt 
All functions matching regular expression "sqrt": 

File ../sysdeps/x86_64/fpu/e_sqrt.c: 
double __ieee754_sqrt(double); 

File s_csqrt.c: 
complex double __csqrt(complex double); 

File ../sysdeps/x86_64/fpu/e_sqrtf.c: 
float __ieee754_sqrtf(float); 

File w_sqrtf.c: 
float __sqrtf(float); 

File s_csqrtf.c: 
complex float __csqrtf(complex float); 

File ../sysdeps/i386/fpu/e_sqrtl.c: 
long double __ieee754_sqrtl(long double); 

File w_sqrtl.c: 
long double __sqrtl(long double); 

File s_csqrtl.c: 
complex long double __csqrtl(complex long double); 

File ../sysdeps/ieee754/dbl-64/mpsqrt.c: 
void __mpsqrt(mp_no *, mp_no *, int); 

File w_sqrt.c: 
double __sqrt(double); 

(gdb) p __sqrt 
$4 = {double (double)} 0x7ffff7b7fb50 <__sqrt> 

注:__sqrt是在同一地址爲sqrt,但GDB知道它的類型!

(gdb) p __sqrt(3) 
$5 = 1.7320508075688772 
(gdb) p __sqrt(3.0) 
$6 = 1.7320508075688772 

可以合理地認爲這是GDB中的一個bug。隨意創建一個在GDB bugzilla

+0

有趣。我繼續安裝'glibc-debuginfo'(希望這是你的意思,因爲我找不到libc-debuginfo),我也看到'__sqrt'的函數原型。 'print __sqrt(3)'確實返回一個有效的結果。我將這個bug報告給GDB開發人員,除了我幾乎沒有報告錯誤的經驗之外,我對GDB的內部工作知之甚少,無法爲開發人員提供有用的信息。無論如何,謝謝......我正在接受你的答案! – Pieter 2011-02-28 08:11:56

+0

的GDB bug已提交:http://sourceware.org/bugzilla/show_bug.cgi?id=14757 – 2012-10-25 06:39:25

0
#include <stdio.h>                                          
#include <math.h> 

int main() 
{ 
    printf("sqrt(3): %f\n", sqrt(3)); 

    return 0; 
} 

輸出:

[email protected]:~/scratch$ ./a.out 
sqrt(3): 1.732051 
+1

您可以在GDB中重現問題嗎?啓動GDB並在控制檯中輸入'print sqrt(3.0)'。 – Pieter 2011-02-25 21:31:53

7

我預測,你沒有做#include <math.h>

沒有一個函數聲明,C將一個函數的返回值默認爲int。取決於int的大小,浮點數可能會回到0。 C也不知道如何轉換函數參數。它會默認將參數傳遞爲它所發生的類型。如果您傳遞一個整數到sqrt()它不會被轉換爲雙精度,但sqrt()函數將解釋位模式爲double

+0

+1,不僅返回值瘋狂。如果沒有原型,參數也不會轉換爲「double」。所以'sqrt'會看到一些奇怪的位模式,它被解釋爲'double',然後在寄存器中返回一個double,並且調用者在其他一些(整數)寄存器中獲取該值。 – 2011-02-25 21:11:06

+0

我確實包含'math.h',並且確實鏈接了'-lm'。 – Pieter 2011-02-26 20:13:49

0

也許不支持調用sqrt!也許是因爲它是一個libc函數。我不知道的深層原因,但下面的測試顯示了一個有趣的現象:

double mysqrt(double x) { return sqrt(x) }; 

然後在GDB會話:

(gdb) p mysqrt(3) 
$1 = 1.7320508075688772 
(gdb) p sqrt(3) 
$2 = -1209775368 
1

要調用沒有調試信息的函數,必須使用函數指針cast來顯式地告訴gdb返回值和參數的類型。因此,例如:

(gdb) print ((double (*) (double)) sqrt) (3) 
$1 = 1.7320508075688772 
+0

打印(雙)SQRT((雙)3) 返回 $ 6 = 1 我懷疑結果首先轉換爲int,然後轉換爲double .. – user1656671 2016-10-17 11:55:44

相關問題