Nếu bạn đang tìm kiếm một ràng buộc tốt cho lỗi làm tròn của mình, bạn không nhất thiết cần một thư viện chính xác. Bạn có thể sử dụng phân tích lỗi chạy thay thế.
Tôi không thể tìm thấy một tài liệu tham khảo trực tuyến tốt, nhưng tất cả được mô tả trong Phần 3.3 của cuốn sách "Độ chính xác và ổn định của thuật toán số" của Nick Higham. Ý tưởng khá đơn giản:
- Xác định lại mã của bạn để bạn có một phép gán duy nhất cho một phép toán số học trên mỗi dòng.
- Đối với mỗi biến, ví dụ:
x
tạo một biến x_err
được khởi tạo về 0 khi x
được gán một hằng số.
- Đối với mỗi hoạt động, ví dụ
z = x * y
, cập nhật biến z_err
bằng mô hình chuẩn của số học dấu phẩy động và kết quả z
cũng như các lỗi đang chạy x_err
và y_err
.
- Giá trị trả về của hàm của bạn sau đó cũng sẽ có một
_err
giá trị tương ứng được đính kèm với nó. Đây là một phụ thuộc dữ liệu bị ràng buộc vào tổng số lỗi vòng của bạn.
Phần khó khăn là bước 3. Đối với các phép toán số học đơn giản nhất, bạn có thể sử dụng các quy tắc sau:
z = x + y
-> z_err = u*abs(z) + x_err + y_err
z = x - y
-> z_err = u*abs(z) + x_err + y_err
z = x * y
-> z_err = u*abs(z) + x_err*abs(y) + y_err*abs(x)
z = x / y
-> z_err = u*abs(z) + (x_err*abs(y) + y_err*abs(x))/y^2
z = sqrt(x)
-> z_err = u*abs(z) + x_err/(2*abs(z))
nơi u = eps/2
là đơn vị roundoff. Vâng, các quy tắc cho +
và -
là như nhau. Các quy tắc cho bất kỳ hoạt động nào khác op(x)
có thể được trích xuất dễ dàng bằng cách sử dụng mở rộng chuỗi Taylor của kết quả được áp dụng cho op(x + x_err)
. Hoặc bạn có thể thử googling. Hoặc sử dụng sách của Nick Higham.
Ví dụ, hãy xem xét mã Matlab / Octave sau đây để đánh giá một đa thức trong các hệ số a
tại một điểm x
bằng cách sử dụng sơ đồ Horner:
function s = horner ( a , x )
s = a(end);
for k=length(a)-1:-1:1
s = a(k) + x*s;
end
Bước đầu tiên, chúng tôi chia hai hoạt động trong s = a(k) + x*s
:
function s = horner ( a , x )
s = a(end);
for k=length(a)-1:-1:1
z = x*s;
s = a(k) + z;
end
Sau đó chúng tôi giới thiệu các _err
biến. Lưu ý rằng các đầu vào a
và x
được giả định là chính xác, nhưng chúng tôi cũng có thể yêu cầu người dùng chuyển các giá trị tương ứng cho a_err
và x_err
:
function [ s , s_err ] = horner ( a , x )
s = a(end);
s_err = 0;
for k=length(a)-1:-1:1
z = x*s;
z_err = ...;
s = a(k) + z;
s_err = ...;
end
Cuối cùng, chúng tôi áp dụng các quy tắc được mô tả ở trên để có được các điều khoản lỗi:
function [ s , s_err ] = horner ( a , x )
u = eps/2;
s = a(end);
s_err = 0;
for k=length(a)-1:-1:1
z = x*s;
z_err = u*abs(z) + s_err*abs(x);
s = a(k) + z;
s_err = u*abs(s) + z_err;
end
Lưu ý rằng vì chúng tôi không có a_err
hoặc x_err
, ví dụ như chúng được coi là 0, các thuật ngữ tương ứng chỉ đơn giản được bỏ qua trong các biểu thức lỗi.
Et voilà! Bây giờ chúng ta có sơ đồ Horner trả về ước tính lỗi phụ thuộc dữ liệu (lưu ý: đây là giới hạn trên của lỗi) cùng với kết quả.
Một lưu ý phụ, vì bạn đang sử dụng C ++, bạn có thể xem xét tạo lớp của riêng mình cho các giá trị dấu phẩy động mang theo _err
thuật ngữ và làm quá tải tất cả các phép toán số học để cập nhật các giá trị này như được mô tả ở trên. Đối với các mã lớn, đây có thể là tuyến dễ dàng hơn, mặc dù tính toán kém hiệu quả hơn. Có nói rằng, bạn có thể tìm thấy một lớp học trực tuyến như vậy. Một tìm kiếm nhanh trên Google đã cho tôi liên kết này .
± ux ( 1 ± u )