2016-06-04 25 views
8

Tôi đang làm việc với một loạt các đôi gọi là indata (trong đống, phân bổ với malloc), và một đôi địa phương gọi là sum.C nguyên tắc cơ bản: biến kép không bằng biểu thức kép?

Tôi đã viết hai hàm khác nhau để so sánh các giá trị trong indata và nhận được các kết quả khác nhau. Cuối cùng tôi đã xác định rằng sự khác biệt là do một hàm sử dụng một biểu thức trong một phép thử có điều kiện và hàm kia sử dụng một biến cục bộ trong cùng một phép thử có điều kiện. Tôi mong đợi những điều này tương đương.

chức năng Mỹ Á sử dụng:

if (indata[i]+indata[j] > max) hi++; 

và chức năng của tôi B sử dụng:

sum = indata[i]+indata[j]; 
    if (sum>max) hi++; 

Sau khi đi qua cùng một tập dữ liệu và max, tôi kết thúc với giá trị khác nhau của hi tùy thuộc vào chức năng tôi sử dụng. Tôi tin rằng hàm B là đúng, và hàm A là gây hiểu nhầm. Tương tự như vậy khi tôi thử đoạn mã bên dưới

sum = indata[i]+indata[j]; 
    if ((indata[i]+indata[j]) != sum) etc. 

điều kiện đó sẽ đánh giá là đúng.

Mặc dù tôi hiểu rằng các số dấu phẩy động không nhất thiết cung cấp biểu diễn chính xác, tại sao thay đổi biểu diễn chính xác khi được đánh giá dưới dạng biểu thức so với được lưu trữ trong một biến? Được khuyến cáo thực hành tốt nhất để luôn luôn đánh giá một biểu thức kép như thế này trước khi có điều kiện? Cảm ơn!

+0

Về cơ bản, máy tính không thể đại diện cho các con số có tổng độ chính xác. Đọc về dấu chấm động. –

+0

@iharob Ông thừa nhận rằng trong đoạn cuối của mình. Nhưng nó không giải thích tại sao nó khác nhau tùy thuộc vào việc bạn gán kết quả cho một biến. – Barmar

+0

Điều này có được biên dịch cho x86 hoặc x86-64 không? – Dolda2000

Trả lời

12

Tôi nghi ngờ bạn đang sử dụng 32-bit x86, kiến ​​trúc chung duy nhất chịu độ chính xác vượt quá. Trong C, các biểu thức thuộc loại floatdouble thực sự được đánh giá là float_t hoặc double_t, có mối quan hệ với floatdouble được phản ánh trong macro FLT_EVAL_METHOD. Trong trường hợp x86, cả hai đều được định nghĩa là long double vì fpu không thực sự có khả năng thực hiện số học ở độ chính xác đơn hoặc kép. (Nó có các bit chế độ nhằm mục đích cho phép điều đó, nhưng hành vi đó hơi sai và do đó không thể sử dụng được.)

Chỉ định cho một đối tượng kiểu float hoặc double là một cách để buộc làm tròn và loại bỏ phần thừa chính xác, nhưng bạn cũng có thể chỉ cần thêm một diễn viên vô cớ vào (double) nếu bạn muốn để nó như là một biểu thức mà không có bài tập.

Lưu ý rằng buộc làm tròn đến độ chính xác mong muốn không tương đương với việc thực hiện số học theo độ chính xác mong muốn; thay vì một bước làm tròn (trong số học) bây giờ bạn có hai (trong số học, và một lần nữa để giảm độ chính xác không mong muốn), và trong trường hợp làm tròn đầu tiên cho bạn một điểm chính xác, làm tròn thứ hai có thể đi sai ' phương hướng. Vấn đề này thường được gọi là làm tròn đôi và làm cho độ chính xác vượt quá đáng kể so với độ chính xác danh nghĩa đối với một số loại phép tính nhất định.

+0

Cảm ơn lời giải thích. Tôi đang chạy mã trên một CPU i7-3770 chạy 64-bit Windows 7. Tuy nhiên, trình biên dịch của tôi là minGW, đó là một ứng dụng 32 bit. Tôi sẽ điều tra các thiết lập trình biên dịch. Tôi hiểu rằng có một mức độ chính xác phần cứng cao hơn gấp đôi và sẽ cẩn thận hơn khi sử dụng các biểu thức so với các biến. FYI, loại đúc biểu thức thực sự không hoạt động trong trường hợp này - cùng một hành vi như không có nó. – stilllearning

+1

Thử dàn diễn viên với '-std = c99' hoặc' -fexcess-precision = standard'. Trong một số chế độ không phù hợp tiêu chuẩn GCC nhận hành vi sai. –

+0

Cảm ơn bạn - một trong các tùy chọn dòng lệnh trình biên dịch đó khắc phục sự cố, để mã này hoạt động chính xác: 'if ((double) (indata [i] + indata [j])> max) hi ++;' – stilllearning

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