2016-10-04 18 views
6

là việc bổ sung x + x hoán đổi cho nhau bởi những nhân 2 * x trong IEEE 754 (IEC 559) dấu chấm động chuẩn, hoặc tổng quát hơn nói là có gì đảm bảo rằng case_addcase_mulluôn cho kết quả chính xác giống nhau?năng hoán đổi của IEEE 754 floating-point cộng và phép nhân

#include <limits> 

template <typename T> 
T case_add(T x, size_t n) 
{ 
    static_assert(std::numeric_limits<T>::is_iec559, "invalid type"); 

    T result(x); 

    for (size_t i = 1; i < n; ++i) 
    { 
     result += x; 
    } 

    return result; 
} 

template <typename T> 
T case_mul(T x, size_t n) 
{ 
    static_assert(std::numeric_limits<T>::is_iec559, "invalid type"); 

    return x * static_cast<T>(n); 
} 
+0

Lưu ý rằng hình như vẫn có nhiều cách để tổng hợp n * x, nhưng đáng ngạc nhiên rất nhiều tương đương! Đây là bằng cách nào đó liên quan đến http://stackoverflow.com/questions/21690585/is-3xx-always-exact và http://stackoverflow.com/questions/21676955/floating-point-product-expansion-equivalence –

Trả lời

9

là việc bổ sung x + x hoán đổi cho nhau bởi những nhân 2 * x trong IEEE 754 (IEC 559) dấu chấm động chuẩn

Có , vì cả hai đều giống nhau về mặt toán học, nên chúng sẽ cho kết quả tương tự (vì kết quả là chính xác trong dấu phẩy động).

hoặc nói chung hơn là có bất kỳ đảm bảo nào case_add và case_mul luôn cung cấp chính xác cùng một kết quả không?

Thông thường, không. Từ những gì tôi có thể nói, có vẻ như để giữ cho n <= 5:

  • n=3: như x+x là chính xác (ví dụ liên quan đến việc không làm tròn), do đó (x+x)+x chỉ liên quan đến một tròn ở bước cuối cùng.
  • n=4 (và bạn đang sử dụng chế độ làm tròn mặc định) sau đó

    • nếu các bit cuối cùng của x là 0, sau đó x+x+x là chính xác, và do đó kết quả đều bình đẳng bởi lập luận tương tự như n=3.
    • nếu 2 bit cuối cùng là 01, thì giá trị chính xác của x+x+x sẽ có 2 bit cuối cùng là 1|1 (trong đó | cho biết bit cuối cùng trong định dạng), sẽ được làm tròn thành 0|0. Việc bổ sung tiếp theo sẽ cho kết quả chính xác |01, do đó kết quả sẽ được làm tròn xuống, hủy bỏ lỗi trước đó.
    • nếu 2 bit cuối cùng là 11, thì giá trị chính xác của x+x+x sẽ có 2 bit cuối cùng của 0|1, sẽ được làm tròn xuống 0|0. Lần bổ sung tiếp theo sẽ cho kết quả chính xác |11, do đó kết quả sẽ được làm tròn lên, một lần nữa hủy bỏ lỗi trước đó.
  • n=5 (một lần nữa, giả định mặc định làm tròn): kể từ x+x+x+x là chính xác, nó giữ với lý do tương tự như n=3.

Đối với n=6 không thành công, ví dụ: mất x1.0000000000000002 (tiếp theo double sau 1.0), trong trường hợp này là 6x6.000000000000002x+x+x+x+x+x6.000000000000001

+0

Wow bằng chứng của bạn là ngắn hơn nhiều so với bằng chứng của tôi bằng cách phân tích trường hợp về việc 3 * x là trong cùng một binade như 2 * x hoặc 4 * x. –

+1

Câu trả lời chi tiết tuyệt vời với bằng chứng về tính chính xác. – plasmacel

+1

Từ những gì tôi có thể biết dựa trên các thử nghiệm toàn diện với IEEE-754 'binary32' (=' float'), phép nhân * n * giống với * (n-1) * lần lặp lại khi * n * ≤ 5 cho 'FE_TONEAREST ', * n * ≤ 3 cho' FE_TOWARDZERO', * n * ≤ 3 cho 'FE_DOWNWARD' và * n * ≤ 3 cho' FE_UPWARD'. Là bằng chứng mở rộng để chế độ làm tròn hướng? – njuffa

3

Nếu n là ví dụ pow(2, 54) thì nhân sẽ chỉ làm việc tốt, nhưng trong đường dẫn bổ sung một lần giá trị kết quả là đủ lớn hơn đầu vào x, result += x sẽ mang lại result.

1

Có, nhưng nó không nắm giữ chung. Nhân với số cao hơn 2 có thể không cho kết quả tương tự, vì bạn đã thay đổi số mũ và có thể giảm một chút nếu bạn thay thế bằng số cộng. Nhân đôi bởi hai không thể thả một chút nếu thay thế bằng cách thêm hoạt động, tuy nhiên.

1

Nếu bộ tích lũy result trong case_add trở nên quá lớn, thêm x sẽ giới thiệu lỗi làm tròn. Tại một thời điểm nhất định, việc thêm x sẽ không có tác dụng. Vì vậy, các chức năng sẽ không cho kết quả tương tự.

Ví dụ nếu double x = 0x1.0000000000001p0 (ký hiệu phao thập lục phân):

n case_add    case_mul 

1 0x1.0000000000001p+0 0x1.0000000000001p+0 
2 0x1.0000000000001p+1 0x1.0000000000001p+1 
3 0x1.8000000000002p+1 0x1.8000000000002p+1 
4 0x1.0000000000001p+2 0x1.0000000000001p+2 
5 0x1.4000000000001p+2 0x1.4000000000001p+2 
6 0x1.8000000000001p+2 0x1.8000000000002p+2 
Các vấn đề liên quan