我在Geforce GTX 580(Fermi)上使用CUDA 4.0。我的数字小到7.721155e-43。我想将它们相互增加一次或者更好地说我想计算7.721155e-43 * 7.721155e-43。
我的经验告诉我,我不能直接做到这一点。你能给我一个建议吗?我需要使用双精度吗?怎么样?
答案 0 :(得分:5)
最小正常IEEE单精度数的大小约为1.18e-38,最小的非正规数会使你降低到大约1.40e-45。作为结果,7.82e-43的操作数将仅包括大约9个非零位,这本身可能已经成为问题,甚至在进行乘法之前(其结果将在单精度中下溢到零)。因此,您可能还希望查看产生这些微小数字的任何上游计算。
如果这些小数字是数学表达式中的中间项,则将该表达式重写为不涉及微小中间体的数学上等价的表达将是解决该问题的一种方法。或者你可以通过2的幂的因子来缩放一些操作数(以便不会因缩放而产生额外的舍入)。例如,缩放比例为2 ^ 24 = 16777216。
最后,您可以将部分计算切换为双精度。为此,只需引入double类型的临时变量,对它们执行计算,然后将最终结果转换回float:
float r, f = 7.721155e-43f;
double d, t;
d = (double)f; // explicit cast is not necessary, since converting to wider type
t = d * d;
[... more intermediate computation, leaving result in 't' ...]
r = (float)t; // since conversion is to narrower type, cast will avoid warnings
答案 1 :(得分:0)
在统计数据中,我们经常需要处理最终非常小数的可能性,标准技术是使用日志来处理所有事情。然后在对数标度上的乘法只是加法。所有中间数字都存储为日志。实际上,它可能需要一些习惯 - 但即使在进行相对适度的计算时,替代方案通常也会失败。在R(为了我的方便!)使用双打并默认打印7个有效数字btw:
> 7.721155e-43 * 7.721155e-43
[1] 5.961623e-85
> exp(log(7.721155e-43) + log(7.721155e-43))
[1] 5.961623e-85