ฉันลองใช้ตัวอย่างที่รุนแรงในคำตอบที่ Steve Jessop ให้มา
#include <iostream>
#include <iomanip>
#include <cmath>
int main()
{
long billion = 1000000000;
double big = 1.0;
double small = 1e-9;
double expected = 2.0;
double sum = big;
for (long i = 0; i < billion; ++i)
sum += small;
std::cout << std::scientific << std::setprecision(1) << big << " + " << billion << " * " << small << " = " <<
std::fixed << std::setprecision(15) << sum <<
" (difference = " << std::fabs(expected - sum) << ")" << std::endl;
sum = 0;
for (long i = 0; i < billion; ++i)
sum += small;
sum += big;
std::cout << std::scientific << std::setprecision(1) << billion << " * " << small << " + " << big << " = " <<
std::fixed << std::setprecision(15) << sum <<
" (difference = " << std::fabs(expected - sum) << ")" << std::endl;
return 0;
}
ฉันได้ผลลัพธ์ดังต่อไปนี้:
1.0e+00 + 1000000000 * 1.0e-09 = 2.000000082740371 (difference = 0.000000082740371)
1000000000 * 1.0e-09 + 1.0e+00 = 1.999999992539933 (difference = 0.000000007460067)
ข้อผิดพลาดในบรรทัดแรกจะใหญ่กว่าในบรรทัดที่สองสิบเท่า
หากฉันเปลี่ยนdouble
s เป็นfloat
s ในโค้ดด้านบนฉันจะได้รับ:
1.0e+00 + 1000000000 * 1.0e-09 = 1.000000000000000 (difference = 1.000000000000000)
1000000000 * 1.0e-09 + 1.0e+00 = 1.031250000000000 (difference = 0.968750000000000)
ไม่มีคำตอบใดที่ใกล้เคียงกับ 2.0 (แต่ข้อที่สองใกล้กว่าเล็กน้อย)
การใช้การสรุป Kahan (พร้อมdouble
s) ตามที่ Daniel Pryden อธิบายไว้:
#include <iostream>
#include <iomanip>
#include <cmath>
int main()
{
long billion = 1000000000;
double big = 1.0;
double small = 1e-9;
double expected = 2.0;
double sum = big;
double c = 0.0;
for (long i = 0; i < billion; ++i) {
double y = small - c;
double t = sum + y;
c = (t - sum) - y;
sum = t;
}
std::cout << "Kahan sum = " << std::fixed << std::setprecision(15) << sum <<
" (difference = " << std::fabs(expected - sum) << ")" << std::endl;
return 0;
}
ฉันได้รับ 2.0:
Kahan sum = 2.000000000000000 (difference = 0.000000000000000)
และแม้ว่าฉันจะเปลี่ยนdouble
s เป็นfloat
s ในโค้ดด้านบนฉันจะได้รับ:
Kahan sum = 2.000000000000000 (difference = 0.000000000000000)
ดูเหมือนว่า Kahan จะเป็นหนทางไป!