2012-06-16 27 views
5

Trước hết, xin lỗi cho tiêu đề xấu:/kết quả không mong muốn với chế độ làm tròn cụ thể

Tôi đang cố gắng sao chép kết quả của giấy tính toán giá trị riêng của ma trận đối xứng tridiagonal. Tôi đang xác định một số giá trị 'giới hạn trên và dưới' bằng cách làm tròn để cộng và trừ vô cùng, tương ứng.

Thay vì thay đổi chế độ làm tròn mỗi lần, tôi chỉ sử dụng 'thủ thuật': fl⁻ (y) = -fl⁺ (-y), trong đó fl⁻ (y) là giá trị của y khi sử dụng dấu trừ chế độ làm tròn vô hạn và fl⁺ (y) là giá trị của y khi sử dụng chế độ làm tròn cộng với vô cùng. Vì vậy, tôi có đoạn mã sau trong C:

fesetround(FE_UPWARD); 
first = - (-d[i] + x); 
second = (- ((e[i-1]*e[i-1])/a_inf)); 
a_inf = first + second; 

first = d[i] - x; 
second = - ((e[i-1]*e[i-1])/a_sup); 
a_sup = first + second; 

và nó hoạt động tốt ngoại trừ một ví dụ trong đó a_inf mang lại cho tôi những kết quả đúng, nhưng a_sup cho kết quả sai, mặc dù cả hai biến đầu tiên và thứ hai dường như có cùng giá trị.

Tuy nhiên, nếu tôi làm như thế này:

fesetround(FE_UPWARD); 
    first = - (-d[i] + x); 
    second = (- ((e[i-1]*e[i-1])/a_inf)); 

    fesetround(FE_DOWNWARD); 
    first = - (-d[i] + x); 
    second = (- ((e[i-1]*e[i-1])/a_sup)); 

tôi nhận được kết quả ngay. Vì vậy, nếu tôi sử dụng các trick fl⁻ (y) = -fl⁺ (-y), tôi nhận được kết quả đúng, nếu tôi thay đổi chế độ làm tròn và sử dụng biểu thức ban đầu tôi nhận được kết quả sai. Bất kỳ ý tưởng tại sao?

Trong cả hai trường hợp, các biến đầu tiên và giá trị thứ hai như sau:

first 1.031250000000000e+07, second -1.031250000000000e+07 
first 1.031250000000000e+07, second -1.031250000000000e+07 

Và các giá trị chính xác cho a_inf và a_sup là -1.862645149230957e-09 và + 1.862645149230957e-09, tương ứng, nhưng trong trường hợp a_sup đầu tiên = 0, đó là sai

gì tôi đoán nó đang xảy ra là một số loại hủy thảm khốc, nhưng tôi không có ý tưởng về làm thế nào để giải quyết nó trong trường hợp này ...

Cảm ơn nâng cao!

+0

Ngôn ngữ này có thuyết bất khả tri không? – Lion

+0

oops, quên rằng: /, tôi đã chỉnh sửa, đó là C. –

+0

Vui lòng kiểm tra thời gian chạy để đặt chế độ làm tròn thành công. Tôi đã thấy nó trước đó 'fesetround' không có hiệu lực trên chế độ làm tròn. Một cái gì đó như 'test_rounding()' trong [ở đây] (http://reliablecomputing.eu/rigorousLP.c). Xin vui lòng tắt tối ưu hóa trình biên dịch hoàn toàn, nó được biết là mess up mọi thứ. – Ali

Trả lời

1

Vấn đề đầu tiên bạn gặp phải là bạn chỉ sử dụng 'lừa' để làm tròn số first về phía -inf và không second, vì vậy nó vẫn được làm tròn theo hướng + inf.

Vấn đề thứ hai là C không cung cấp cho bạn bất kỳ loại bảo đảm nào về cách tính toán dấu chấm động. Đặc biệt, trình biên dịch được tự do sắp xếp lại và liên kết lại các hoạt động vì nó thấy phù hợp với hiệu năng, ngay cả khi các sắp xếp lại đó có thể thay đổi hành vi làm tròn của chương trình. Vì vậy, khi bạn nói:

first = - (-d[i] + x); 

trình biên dịch có thể sắp xếp lại và thực hiện phép trừ đơn, thay vì phủ nhận, thêm, phủ nhận, đảo ngược hướng làm tròn. Bây giờ bạn đôi khi có thể làm cho mọi thứ hoạt động theo cách bạn mong đợi bằng cách vô hiệu hóa tất cả tối ưu hóa, nhưng ngay cả với điều đó, không có sự đảm bảo nào.

+0

+1 Đó là những gì tôi đã đề cập đến trong bình luận của tôi, tối ưu hóa trình biên dịch có thể làm hỏng mọi thứ. – Ali

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