2014-12-07 21 views
19

Tôi không thể giải thích hành vi của chương trình sau (được biên dịch với gcc trên mingw 32 bit). Tôi nhận thức được sự mất mát chính xác có thể khi chuyển đổi hoàn toàn từ đôi thành int, nhưng tôi hy vọng hai trường hợp sẽ cho ra cùng một đầu ra vì nó đang thực hiện các phép toán tương tự. Tại sao hai đầu ra khác nhau?Đôi để int chuyển đổi tiềm ẩn trong mingw32

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

int main() 
{ 
    int table[3] = {2, 3, 4}; 
    int i, N; 

    N = 0; 
    N += table[0] * pow(100, 0); 
    N += table[1] * pow(100, 1); 
    N += table[2] * pow(100, 2); 
    printf("%d\n", N); 

    N = 0; 
    for(i = 0; i < 3; i++) 
     N += table[i] * pow(100, i); 
    printf("%d\n", N); 

    return 0; 
} 

//output: 
40302 
40300 

Trả lời

14

Với pow(100, 0)pow(100, 1)pow(100, 2) trình biên dịch thay thế chức năng cuộc gọi với các hằng số (1, 100, 10000), nhưng với pow(100, i) nó có để thực sự gọi hàm trong thời gian chạy (vì biến i được thông qua như là đối số), kết quả với hai kết quả của pow ở dạng 0.9999999999.999999 thay vì 1100 (hoặc bất kỳ 2 trong số 3). Khi cắt ngắn để int sau khi nhân bạn "mất" hai đơn vị.

Đây là một ví dụ khác về việc tại sao chuyển sang int từ double chỉ là tinh khiết ác: rất khó để tìm lỗi vi tế trong chương trình của bạn (không phải trình biên dịch lỗi).

Btw, tôi ngạc nhiên rằng trình biên dịch với O2 không bỏ vòng lặp, truyền các hằng số và đạt được cùng một tối ưu hóa (thay thế cuộc gọi hàm với kết quả không đổi).

Btw2 Gãi điều đó, tôi ngạc nhiên khi trình biên dịch không chỉ thay thế tất cả các mã của bạn mà chỉ có hai cuộc gọi đến printf.

+0

Tôi nghĩ rằng điều đáng nói đến là tiêu chuẩn C thực sự không chỉ định độ chính xác của "pow()", thậm chí không "pow()" phải đưa ra kết quả tương tự cho pow (0) và pow (i) với i = 0. Điều đó thực sự gây ngạc nhiên cho tôi nhưng có ý nghĩa để cho phép tối ưu hóa trên các hệ thống nhúng rất nhỏ. –

Các vấn đề liên quan