双倍的 Pow 实现

Posted

技术标签:

【中文标题】双倍的 Pow 实现【英文标题】:Pow implementation for double 【发布时间】:2012-07-16 11:52:21 【问题描述】:

我正在开发用于运动控制的代码,但我遇到了 pow 函数的问题。 我正在使用 VS2010 作为 IDE。

这是我的问题: 我有:

    double p = 100.0000;
    double d = 1000.0000;
    t1 = pow((p/(8.0000*d),1.00/4.000);

在评估最后一个函数时,我没有得到更好的近似结果。我得到了正确的 7 位十进制数字,随后的数字都是垃圾。 我猜 pow 函数只会将任何输入变量转换为浮点数并进行计算。

    我说的对吗? 如果是这样,是否有任何代码可以“启发”我重新实现 pow 以获得更好的精度?

编辑:已解决。

毕竟,我遇到了 FPU 配置位问题,这是由 OGRE 3D 框架使用的 Direct3D 引起的。

如果使用 OGRE,在配置 GUI 上,只需设置“Floating-point mode=Consistent”。

如果使用原始 Direct3D,在调用 CreateDevice 时,请确保将“D3DCREATE_FPU_PRESERVE”标志传递给它。

原帖:

您可能正在使用正在更改默认精度的库 FPU 为单精度。然后所有的浮点运算,甚至 在双精度上,实际上将作为单精度运算执行。

作为测试,你可以尝试调用 _controlfp( _CW_DEFAULT, 0xfffff ); (您需要包括)在执行计算之前 看看你是否得到正确的结果。这将重置浮点 控制字为默认值。请注意,它将重置其他设置 同样,这可能会导致问题。

改变浮点精度的常用库是 Direct3D 9(可能还有其他版本):默认情况下,它会更改 创建设备时将 FPU 转换为单精度。如果使用它,请指定 创建设备时的标志 D3DCREATE_FPU_PRESERVE 以防止它 从改变 FPU 精度。

【问题讨论】:

查看编译器自带的标准库中pow()的原型。 glibc 的pow() 有一个原型,所有doublefloat 版本称为powf() C99 具有 long double 类型以提高精度,但显然是 Microsoft decided to get rid that。 MS C++ 确实有 pow 用于 long double 参数。 gcc 以“50 位”精度 0.33437015248821100321663379872916266322135925292969 生成此文件 我做了...我确实在使用 double pow(double, double)... 但是,我的意思是,您不觉得函数返回精确的 7 个十进制数字很奇怪吗结果,float 类型可以承受的小数位数的确切数目? Excel 给出 (1/80)^(1/4) == 0.334370152488211,这与 Aftnix 使用 gcc 得到的结果和我使用 VS2005 得到的结果一致。此外,您的示例粘贴不好:在 t1 前面加上 double 并修复不平衡的括号。 【参考方案1】:

您是如何确定您只能获得 7 位精度的?您是否打印t1 并指定正确的输出格式?在我的机器上,使用 VS2010,以下代码:

int main()

    double p = 100.0000;
    double d = 1000.0000;
    double t1 = pow(p/(8.0000*d),1.00/4.000);

    printf("t1=%.15f\n", t1); // C
    std::cout << "t1=" << std::setprecision(15) << t1 << '\n'; // C++

产生这个输出:

t1=0.334370152488211
t1=0.334370152488211

【讨论】:

我可以通过分析结果来识别它。我得到了 7 位数字,其他数字都与预期结果不同。我通过使用 interjay 的提示解决了这个问题。【参考方案2】:

您可能正在使用将 FPU 的默认精度更改为单精度的库。然后所有的浮点运算,即使在doubles 上,实际上都将作为单精度运算执行。

作为测试,您可以在执行计算之前尝试调用_controlfp( _CW_DEFAULT, 0xfffff );(您需要包含&lt;float.h&gt;),看看您是否得到正确的结果。这会将浮点控制字重置为默认值。请注意,它还会重置其他设置,这可能会导致问题。

一个更改浮点精度的常用库是 Direct3D 9(可能还有其他版本):默认情况下,它在创建设备时将 FPU 更改为单精度。如果使用,请在创建设备时指定标志D3DCREATE_FPU_PRESERVE,以防止其改变FPU精度。

【讨论】:

Interjay:非常感谢!我正在使用 D3D,终于摆脱了这个可怕的问题! 其他:我正在使用 OGRE 3D 进行渲染。我想读取 FPU 状态,更改它,然后,经过计算,将其更改回来。但这可能不是线程安全的,因为 cpu 在改回之前可能会被抢占。要走的路是什么:尝试通过 OGRE 来实现或尝试一些关键部分的东西?非常感谢,一次又一次! 好的,通过direct3d渲染系统的配置GUI就搞定了。谢谢!!!

以上是关于双倍的 Pow 实现的主要内容,如果未能解决你的问题,请参考以下文章

网卡链路聚合 简单设置实现双倍带宽

如何在 OpenCV 中将图像读取为双倍?

华为OD机试模拟题用 C++ 实现 - 求解连续数列+和最大子矩阵(2023.Q1 双倍快乐)

python pow函数底层实现原理

带有内存测试双倍的模拟实体框架

经典共识PoW的原理及实现