[visual-studio]很奇怪,float 类型参数传递在 windows 中的作用

发布时间: 2014/3/1 4:15:19
注意事项: 本文中文内容可能为机器翻译,如要查看英文原文请点击上面连接.

有一段代码混淆我,这在 windows 中运行 !下面是代码:

#define point_float2uint(x) *((unsigned int *)&x)


float divide_1000(float y)
{
    float v = y / 1000.0f;
    return v;
}

float divide_1000(int y)
{
    float v = float(y) / 1000.0f;
    return v;
}


void float_test(void)
{
    int num[5] = {67975500, 67251500, 67540620, 69435500, 70171500};
    for (int i = 0; i < 5; ++i)
    {
        int a = num[i];
        float af_f = divide_1000(float(a));
        float af_i = divide_1000((a));
        printf("src num:%d,  af_f:%f, %x, af_i:%f, %x\n", num[i], af_f, point_float2uint(af_f), af_i, point_float2uint(af_i));
    }
}

这里是输出,由 vs2005 编译:

src num:67975500,  af_f:67975.507813, 4784src num:67975500,  af_f:67975.507812, 4784c3c1, af_i:67975.507812, 4784c3c1
src num:67251500,  af_f:67251.507812, 478359c1, af_i:67251.507812, 478359c1
src num:67540620,  af_f:67540.625000, 4783ea50, af_i:67540.625000, 4783ea50
src num:69435500,  af_f:69435.507812, 47879dc1, af_i:69435.507812, 47879dc1
src num:70171500,  af_f:70171.507812, 47890dc1, af_i:70171.507812, 47890dc1
c1, af_i:67975.500000, 4784src num:67975500,  af_f:67975.507812, 4784c3c1, af_i:67975.507812, 4784c3c1
src num:67251500,  af_f:67251.507812, 478359c1, af_i:67251.507812, 478359c1
src num:67540620,  af_f:67540.625000, 4783ea50, af_i:67540.625000, 4783ea50
src num:69435500,  af_f:69435.507812, 47879dc1, af_i:69435.507812, 47879dc1
src num:70171500,  af_f:70171.507812, 47890dc1, af_i:70171.507812, 47890dc1
c0
src num:67251500,  af_f:67251.507813, 478359c1, af_i:67251.500000, 478359c0
src num:67540620,  af_f:67540.625000, 4783ea50, af_i:67540.617188, 4783ea4f
src num:69435500,  af_f:69435.507813, 47879dc1, af_i:69435.500000, 47879dc0
src num:70171500,  af_f:70171.507813, 47890dc1, af_i:70171.500000, 47890dc0

问题是: 为什么我使用"divide_1000",在 windows 中得到不同的结果?这是不是我想 !我觉得并不是所有的整数导致不同的但有些就像上面的代码。

这里是输出,通过在 debian 中 gcc4.4.5 comipled:

src num:67975500,  af_f:67975.507812, 4784c3c1, af_i:67975.507812, 4784c3c1
src num:67251500,  af_f:67251.507812, 478359c1, af_i:67251.507812, 478359c1
src num:67540620,  af_f:67540.625000, 4783ea50, af_i:67540.625000, 4783ea50
src num:69435500,  af_f:69435.507812, 47879dc1, af_i:69435.507812, 47879dc1
src num:70171500,  af_f:70171.507812, 47890dc1, af_i:70171.507812, 47890dc1

我得到同样的结果在使用不同的函数"divide_1000"。这是自己想要什么。

解决方法 1:

有很多代码生成设置这里涉及影响的结果。您报告的区别是可测的非优化代码的默认浮点模型 (即"精确"模式) 下时使用的"经典"的 FPU 指令进行浮点计算。

编译器将字面翻译第一次调用: 原始整数值先转换为 float -4 字节浮点值-存储在内存 (作为函数的参数)。这种转换值舍入为 +6.7975504e+7 ,这已经是不精确。后来的 float 值是阅读窗体内存里面的第一个函数,用于进一步的计算。

第二次调用都会传递 int 这个函数,而是直接加载到高精度 FPU 寄存器,用于进一步的计算值。尽管您指定显式转换从 intfloat 里面的第二个函数,编译器决定忽略您的请求。此值从未逐字地转换为 float ,永远不会发生上述的精度损失的含义。

这是什么导致你观察到的差异。

如果你重写你第二个函数,作为

float divide_1000(int y)
{
    float fy = y;
    float v = fy / 1000.0f;
    return v;
}

即添加一个额外的步骤,节省了 float 在内存中,编译器的命名位置的价值将在非优化代码中执行这一步。这将导致要成为完全相同的结果。

再次,以上所述的适用于没有优化,编译时,编译器通常尝试翻译所有语句非常密切 (但不是总是确切地) 的代码。在优化代码中,编译器消除"不必要"的中间转换为 float 和所有"不必要"中间内存存储在两种情况下,产生相同的结果。

您还可能想要尝试与其他浮点的模型 (即"严格"和"快"),看看它是如何影响结果。这些浮点模型存在专门对付像你观察到的一个问题。

如果您更改编译器的代码生成设置,并使其使用 SSE 指令进行浮点运算,结果可能也会改变 (在我差消失而不是 FPU 指令使用 SSE2 指令集时的实验)。

官方微信
官方QQ群
31647020