wee*_*mer 4 c++ floating-point floating-accuracy
设a和b是介于0和1之间的两个数字.如何计算pow(a,10000)/(pow(a,10000)+pow(b,10000))?
例如: - 以下代码给出-nan作为输出而不是0.5
double a = 0.5,b = 0.5;
cout<<pow(a,10000)/(pow(a,10000)+pow(b,10000));
Run Code Online (Sandbox Code Playgroud)
您的问题没有简单的通用解决方案.编写处理非常小和/或非常大数字的计算机程序是一种"科学艺术" - 通常称为数值分析.典型的技巧包括计算前的缩放.
在您的情况下,每个pow(..)舍入为零,因为这是与实际结果最接近的可表示值.之后你做0 /(0 + 0)即NaN,即非数字.
你可以选择长双:
long double a = 0.5;
long double b = 0.5;
long double c =pow(a,10000);
long double d =pow(b,10000);
cout << c << endl;
cout << d << endl;
cout<<c/(c+d);
Run Code Online (Sandbox Code Playgroud)
结果是:
5.01237e-3011
5.01237e-3011
0.5
Run Code Online (Sandbox Code Playgroud)
但这只会有助于"一段时间".稍微增加功率(只是额外的零)并且问题又回来了.
long double a = 0.5;
long double b = 0.5;
long double c =pow(a,100000);
long double d =pow(b,100000);
cout << c << endl;
cout << d << endl;
cout<<c/(c+d);
0
0
nan
Run Code Online (Sandbox Code Playgroud)
因此,您需要自己编写一个非常复杂的类或研究如何在数值分析中处理它.
从这里开始:https://en.wikipedia.org/wiki/Numerical_analysis或https://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic
如果您知道所有三个地方的exp都相同,那么您可以这样做:
double a = 0.5,b = 0.5;
int exp = 10000;
//cout<<pow(a,exp)/(pow(a,exp)+pow(b,exp)); is the same as:
cout<<1/(1+pow(b/a,exp));
Run Code Online (Sandbox Code Playgroud)
对于大多数a和b值,它会更好,但不要期望任何精度.如果a和b略有不同,你会得到0(少于b)或1(b少于a).但NaN部分将得到解决.
此类问题的标准方法是使用日志空间,即将每个数字表示为e x,其中x是您的标准浮点类型:
可以使用log-sum-exp技巧来执行加法/减法(和更一般地求和),即
乘法/除法成为加法/减法
提升到一个权力乘以一个指数:
但在您的特定情况下,您可能最好使用StillLearning答案结尾处建议的方法
Gab*_*han -2
编译器不知道足够的数学知识来简化这样的复杂代码(编译器不知道 pow 实际做了什么,它只知道它是一个接受一种类型并返回另一种类型的函数)。所以实际上是要一步步进行计算的。不幸的是,结果太小,无法放入双精度数中。这就是它返回 NAN 的原因 - 您触发了变量的下溢。
如果你真的需要这样做(我会质疑为什么你需要这种程度的准确性),你需要做一些数学技巧来使用非标准数字系统(例如,而不是存储美元)可以存储便士 - 但使用更高的因子)或者您可以编写自己的数学课程并执行所有自己的数学库。
或者您可以迁移到 Mathematica 或 MatLab 这样的平台,它们更适合此类工作,并且内置了很多此类问题。