2009-02-22 38 views
7

Tôi nhận được kết quả không mong muốn từ các hàm round()roundf() trong thư viện math.h. Đây là đoạn mã mẫu:Làm cách nào để sử dụng hàm round() trong C?

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

int main(void) 
{ 
    float f; 
    double d; 

    /* Note man page says that roundf() returns a float 
     and round() returns a double */ 
    f = roundf(1.2); 
    d = round(1.2); 

    printf("%f\n", f); 
    printf("%lf\n", d); 

    return 0; 
} 

Khi tôi complie và chạy chương trình tôi nhận được:

gcc -lm round.c 
./a.out 
288.000000 
524288.000000 

Weird huh?

Cập nhật: Cùng với câu trả lời tôi đã xác nhận rằng mã hoạt động đúng trên trình chỉnh sửa mới hơn. (Tôi nghĩ rằng% lf không phải là đúng printf specifier nhưng điều đó không ảnh hưởng đến kết quả cuối cùng trong trường hợp này.) Tôi sẽ cần phải tìm ra lý do tại sao trình biên dịch có thể hành xử theo cách này bởi vì tôi có chạy mã sử dụng vòng() và đã được trình biên dịch trên cùng một máy. Tôi sẽ cập nhật bài đăng khi tôi tìm ra nó.

gcc -v 
Reading specs from /usr/lib/gcc-lib/i386-slackware-linux/2.95.3/specs 
gcc version 2.95.3 20010315 (release) 
+0

Tôi không nhận được hành vi này. Nó xuất ra 1.000000 cho cả hai trường hợp của tôi. – tvanfosson

+0

Upvoted để bù đắp một downvote. Đây là một câu hỏi hoàn toàn hợp lệ. Tôi cũng sẽ hỏi câu hỏi này nếu tôi có hành vi này. –

+0

cập nhật đầy đủ trình biên dịch của bạn. GCC 2.95.3 đã 8 tuổi ... Hàng triệu lỗi đã được sửa chữa trong những năm này. –

Trả lời

10

Bạn có thể thất bại nếu bạn biên dịch mã mà không yêu cầu gcc biên dịch với chế độ C99 (-std=c99) và thông báo cho bạn không biết về chức năng "builtin đặc biệt" (sử dụng -fno-builtin). Sau đó, giả định rằng chức năng round/roundf của bạn được xác định là

int round(); 
int roundf(); 

Vì trước thời điểm C99 chưa có chức năng như vậy nên không có khai báo và khai báo hoàn toàn. Và điều này rõ ràng sẽ thất bại, bởi vì phía gọi xử lý giá trị trả về như một int, trong khi bên callee (trong định nghĩa của các hàm đó trong thư viện liên kết) trả về một float. Ví dụ: tôi nhận được các kết quả này:

[[email protected] cpp]$ ./a.out 
1065353216.000000 
-1048576.000000 
[[email protected] cpp]$ 

Không phải bây giờ bạn nghĩ rằng bạn có thể truyền giá trị trả về cho phao và OK. Vâng, nó tồi tệ hơn. Giá trị trả về thậm chí không được đảm bảo để có bất kỳ điều gì liên quan đến float được trả về. Phía gọi đọc từ một nơi mà nó biết nơi số nguyên được trả về. Nhưng trình biên dịch của bạn có thể trả lại nổi ở một nơi khác (ví dụ, trong một thanh ghi con trỏ nổi) từ phía bên callee. Ở trên có thể thực sự đã làm bất cứ điều gì, bao gồm hủy bỏ chương trình bởi vì nó hoạt động một cách không xác định.

Vì vậy, bạn có thể làm gì để nó hoạt động? Vượt qua biên dịch các std=c99 cờ hoặc sử dụng những cách khác để làm tròn (sàn là một trong số họ) mà không yêu cầu những chức năng

gcc -std=c99 test.c -lm 

Xem manpage của man 3 round. Tuy nhiên, nếu bạn có một GCC rất cũ - tôi không chắc liệu nó hỗ trợ đủ C99 để có chuyển đổi đó. Nhìn vào các macro thử nghiệm tính năng được mô tả trong manpage của vòng sau đó.

+0

Để làm rõ, bạn đã sử dụng arg nào với gcc? – Harry

+0

gcc -lm -fno-builtin test.c –

+0

như bạn nói bạn sử dụng gcc cũ hơn, nó có thể không hỗ trợ biết về các chức năng dựng sẵn đặc biệt (điều trị ví dụ như các cuộc gọi đến memcpy đặc biệt). vì vậy bạn sẽ không cần -fno-buildin để làm cho nó thất bại :) –

3

Khi tôi biên dịch và chạy mã này chính xác (dưới gcc trên Cygwin) tôi nhận được:

$ ./a.exe 
1.000000 
1.000000 

Làm thế nào mới là trình biên dịch của bạn? Lỗi trình biên dịch là tất cả những gì tôi có thể nghĩ đến, vì gcc -Wall cũng không đưa ra cảnh báo nào.

Để thêm một số thông tin khác, this forum thread dường như hiển thị trình biên dịch thay đổi sang phiên bản mới hơn sẽ sửa lỗi đó. Nếu điều này không làm việc cho bạn, bạn sẽ cần phải cung cấp thêm chi tiết về trình biên dịch và hệ điều hành, nhưng điều này dường như làm việc cho những người khác trên ba nền tảng khác nhau trông giống như trình biên dịch của bạn có lỗi.

+0

Tôi đã làm cho nó hoạt động trên một trình duyệt mới hơn. Do hoàn cảnh của tôi, tôi có thể nâng cấp trình biên dịch. – Harry

+0

Hoan hô - tôi có thể chấp nhận câu trả lời sau đó không? –

+0

Hoặc thậm chí là một upvote? –

1

Điều này rõ ràng là không giúp nhưng mã trông và chạy như mong đợi đối với tôi. Mọi thứ đều ổn.

2

Để thêm vào đoạn điệp khúc phê duyệt, điều này phù hợp với tôi (OS X Leopard sử dụng gcc).

Ngoài sự tò mò, bạn có cần sử dụng cờ -lm không? Tôi đã không lần đầu tiên, và tôi đã làm lần thứ hai, và không có sự khác biệt, nhưng đó là bởi vì libm.dylib và libc.dylib là liên kết tượng trưng cho cùng một thư viện trên OS X. Có lẽ libm của bạn bị hỏng hay gì đó? Bạn có cần phải liên kết đến libm hay không? Tôi sẽ nghĩ rằng các hàm math.h sẽ là một phần của libc ...?

EDIT:

Trước khi bạn làm được điều đó, hãy thử sử dụng này để thay thế:

float f = 0; 
double d = 0; 

Tôi không nghĩ rằng nên thay đổi bất cứ điều gì, nhưng nếu có, tôi giành chiến thắng.

+0

Tôi cần phải xác định nó trên Linux nếu không trình biên dịch phàn nàn với "tham chiếu không xác định đến vòng". – Harry

+0

Về mặt kỹ thuật, trình liên kết phàn nàn, không phải trình biên dịch, nhưng tôi hiểu. Tôi đã thêm một giải pháp mới mà MIGHT hoạt động, nhưng có lẽ không. Hãy thử nó cho biện pháp tốt, nhưng nếu không tôi nghĩ rằng libm của bạn bị hỏng. Bạn sẽ cần phải biên dịch một cái mới. –

2

Một thiết bị khác "hoạt động trên máy của tôi" trên Ubuntu với phiên bản gcc 4.3.2.

$ ./a.out 
1.000000 
1.000000 

Tôi nhận được một vài cảnh báo khi tôi biên dịch.

$ gcc -lm round.c 
round.c: In function ‘main’: 
round.c:11: warning: incompatible implicit declaration of built-in function ‘roundf’ 
round.c:12: warning: incompatible implicit declaration of built-in function ‘round’ 
+0

Bạn đã quên #include ? Hoặc có lẽ các hàm round() và roundf() của bạn được lưu trữ trong một tiêu đề khác (không phải là trường hợp)? –

+0

Tôi đã #include , vì vậy tôi không chắc chắn về những cảnh báo. –

0

Có vẻ như bạn đang sử dụng đúng cách, mô tả môi trường của bạn?

2

litb đã đi đúng hướng. -std=c99 không hoạt động nhưng thêm #define _ISOC99_SOURCE đã hoạt động. Vì vậy, mã trông giống như:

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

int main(void) 
{ 
... 
Các vấn đề liên quan