在摆弄log() 并怀疑operator += () 之后,我终于解决了这个难题。
实际错误是由printf("%.5lf\n", ...)引起的。
为了演示,我稍微修改了示例代码:
#include<cmath>
#include<cstdio>
#include<iomanip>
#include<iostream>
using namespace std;
int main() {
int i, p, q, r, s;
while (scanf("%d %d %d %d", &p, &q, &r, &s) == 4) {
long double ans = 0;
if (p - q < q)
q = p - q;
if (r - s < s)
s = r - s;
for (i = 1; i <= q; i++)
ans += log(p - q + i) - log(i);
for (i = 1; i <= s; i++)
ans -= log(r - s + i) - log(i);
printf("printf: %.5lf", exp(ans));
cout << "\tcout: " << fixed << setprecision(5) << exp(ans) << endl;
}
return 0;
}
现在的输出是:
printf: 0.00000 cout: 0.12587
printf: 0.00000 cout: 505606.46055
printf: 0.00000 cout: 1.28223
printf: 0.00000 cout: 0.48996
printf: 0.00000 cout: 2.00000
printf: 0.00000 cout: 3.99960
我在ideone 上检查了这个。
当我在 Windows 10(64 位)上使用 VS2013 编译和运行它时得到相同的输出。
我也在 Windows 10(64 位)的 cygwin 中使用 gcc 进行了检查,得到以下输出:
$ g++ -std=c++11 -o test-longdouble test-longdouble.cc ; echo '10 5 14 9
> 93 45 84 59
> 145 95 143 92
> 995 487 996 488
> 2000 1000 1999 999
> 9998 4999 9996 4998
> ' | ./test-longdouble
printf: -0.00000 cout: 0.12587
printf: -4234002535919089587818586571373347278663379000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.00000 cout: 505606.46055
printf: -0.00000 cout: 1.28223
printf: -65094314467486612925155033958017324735054040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.00000 cout: 0.48996
printf: nan cout: 2.00000
printf: nan cout: 3.99960
$ g++ -std=c++14 -o test-longdouble test-longdouble.cc ; echo '10 5 14 9
93 45 84 59
145 95 143 92
995 487 996 488
2000 1000 1999 999
9998 4999 9996 4998
' | ./test-longdouble
printf: -0.00000 cout: 0.12587
printf: -4234002535919089587818586571373347278663379000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.00000 cout: 505606.46055
printf: -0.00000 cout: 1.28223
printf: -65094314467486612925155033958017324735054040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.00000 cout: 0.48996
printf: nan cout: 2.00000
printf: nan cout: 3.99960
$ g++ --version
g++ (GCC) 5.4.0
第一眼没看到,但cout 输出是正确的,只是printf 输出不同。
考虑到printf 格式化程序选择错误,您不应该对它的效果有任何期望。
然后我修复了printf()中的错误格式:
#include<cmath>
#include<cstdio>
#include<iomanip>
#include<iostream>
using namespace std;
int main() {
int i, p, q, r, s;
while (scanf("%d %d %d %d", &p, &q, &r, &s) == 4) {
long double ans = 0;
if (p - q < q)
q = p - q;
if (r - s < s)
s = r - s;
for (i = 1; i <= q; i++)
ans += log(p - q + i) - log(i);
for (i = 1; i <= s; i++)
ans -= log(r - s + i) - log(i);
printf("printf: %.5Lf", exp(ans));
cout << "\tcout: " << fixed << setprecision(5) << exp(ans) << endl;
}
return 0;
}
在 Windows 10(64 位)的 cygwin 中使用 gcc 再次编译和测试:
$ g++ -std=c++14 -o test-longdouble test-longdouble.cc ; echo '10 5 14 9
93 45 84 59
145 95 143 92
995 487 996 488
2000 1000 1999 999
9998 4999 9996 4998
' | ./test-longdouble
printf: 0.12587 cout: 0.12587
printf: 505606.46055 cout: 505606.46055
printf: 1.28223 cout: 1.28223
printf: 0.48996 cout: 0.48996
printf: 2.00000 cout: 2.00000
printf: 3.99960 cout: 3.99960
因此,我只能重复我在评论中已经说过的内容:您确实应该使用 C++ 流输出。 printf() 可能由于格式化程序中最轻微的错误而导致奇怪的行为。