快速登录C ++ float ...这段代码中是否有任何平台依赖?

时间:2010-03-24 14:26:37

标签: c++ floating-point ieee-754 endianness

在线搜索,我发现以下例程用于计算IEEE格式的浮点符号。这也很容易扩展到双倍。

// returns 1.0f for positive floats, -1.0f for negative floats, 0.0f for zero
inline float fast_sign(float f) {
    if (((int&)f & 0x7FFFFFFF)==0) return 0.f; // test exponent & mantissa bits: is input zero?
    else {
        float r = 1.0f;
        (int&)r |= ((int&)f & 0x80000000); // mask sign bit in f, set it in r if necessary
        return r;
    }
}

Source:``快速签署32位花车'',Peter Schoffhauzer)

但是,由于二进制位操作,我厌倦了使用这个例程。我需要我的代码在具有不同字节顺序的机器上工作,但我不确定IEEE标准中有多少指定,因为我找不到今年发布的最新版本。有人能告诉我这是否有效,无论机器的字节顺序如何?

谢谢, 帕特里克

2 个答案:

答案 0 :(得分:10)

您如何看待fabs()fabsf()在您的系统上实施,或者与常数0进行比较?如果它不是按位运算,那很可能是因为编译器编写者认为不会更快。

此代码的可移植性问题是:

  1. float和int可能没有相同的字节序或甚至相同的大小。因此,面具可能是错误的。
  2. float可能不是IEEE表示
  3. 您打破严格的别名规则。允许编译器假定指向float的指针/引用和指向int 的指针/引用不能指向同一内存位置。因此,例如,标准不保证r在以下行中修改之前已初始化为1.0。它可以重新排序操作。这不是空闲的推测,并且与(1)和(2)不同,它是未定义的,而不是实现定义的,因此您不一定只需查找编译器。通过足够的优化,我看到GCC跳过了浮点变量的初始化,这些浮点变量只能通过类型惩罚指针来引用。
  4. 我会先做明显的事情并检查发出的代码。只有这看起来狡猾,才值得考虑做其他事情。我没有任何特别的理由认为我知道浮点数的位数表示比我的编译器更多; - )

    inline float fast_sign(float f) {
        if (f > 0) return 1;
        return (f == 0) ? 0 : -1;
        // or some permutation of the order of the 3 cases
    }
    

    [编辑:实际上,即使用-O3,海湾合作委员会也确实做了一顿饭。发出的代码不一定很慢,但它确实使用了浮点运算,因此不清楚它是否很快。因此,下一步是进行基准测试,测试替代方案是否可以更快地在您可以使用的任何编译器上进行测试,如果是这样,那么移植代码的人可以通过#define或其他方式启用它们,根据他们自己的基准测试结果。]

答案 1 :(得分:3)

不要忘记将浮点值从FPU寄存器移动到整数寄存器需要写入RAM然后读取。

使用浮点代码,您可以更好地查看更大的图片:

Some floating point code
Get sign of floating point value
Some more floating point code

在上面的场景中,使用FPU确定符号会更快,因为没有写/读开销 1 。英特尔FPU可以:

FLDZ
FCOMP

设置> 0< 0== 0的条件代码标记,可以与FCMOVcc一起使用。

将上述内容写入编写良好的FPU代码将胜过任何整数位操作,并且不会丢失精度 2

注意:

  1. 英特尔IA32确实具有读写后优化功能,它不会等待数据提交到RAM /缓存,而只是直接使用该值。它仍然会使缓存无效,但会产生连锁反应。
  2. 英特尔FPU内部为80位,浮点数为32,双倍64,因此转换为float / double以重新加载为整数将失去一些精度。当你正在寻找0左右的过渡时,这些是重要的一点。