将double转换为float而不依赖于FPU舍入模式

Pas*_*uoq 5 c floating-point bit-manipulation ieee-754

有没有人有方便的代码片段将IEEE 754 double转换为直接低级(相应的高级)float,而不改变或假设FPU的当前舍入模式

注意:此约束可能意味着根本不使用FPU.我希望在这些条件下最简单的方法是读取64位长的双位并使用它.

为简单起见,您可以假设您选择的字节顺序,并且可以通过d下面的联合字段获得所讨论的双重字符:

union double_bits
{
  long i;
  double d;
};
Run Code Online (Sandbox Code Playgroud)

我会尝试自己做,但我确信我会为非规范化或负数引入难以察觉的错误.

Alo*_*hal 3

我认为以下方法可行,但我会首先陈述我的假设:

  • 浮点数在您的实现中以 IEEE-754 格式存储,
  • 没有溢出,
  • 你有nextafterf()可用的(它在C99中指定)。

而且,这种方法很可能不是很有效。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(int argc, char *argv[])
{
    /* Change to non-zero for superior, otherwise inferior */
    int superior = 0;

    /* double value to convert */
    double d = 0.1;

    float f;
    double tmp = d;

    if (argc > 1)
        d = strtod(argv[1], NULL);

    /* First, get an approximation of the double value */
    f = d;

    /* Now, convert that back to double */
    tmp = f;

    /* Print the numbers. %a is C99 */
    printf("Double: %.20f (%a)\n", d, d);
    printf("Float: %.20f (%a)\n", f, f);
    printf("tmp: %.20f (%a)\n", tmp, tmp);

    if (superior) {
        /* If we wanted superior, and got a smaller value,
           get the next value */
        if (tmp < d)
            f = nextafterf(f, INFINITY);
    } else {
        if (tmp > d)
            f = nextafterf(f, -INFINITY);
    }
    printf("converted: %.20f (%a)\n", f, f);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在我的机器上,它打印:

Double: 0.10000000000000000555 (0x1.999999999999ap-4)
Float: 0.10000000149011611938 (0x1.99999ap-4)
tmp: 0.10000000149011611938 (0x1.99999ap-4)
converted: 0.09999999403953552246 (0x1.999998p-4)
Run Code Online (Sandbox Code Playgroud)

我的想法是,我将该double值转换为一个float值,该值可能小于或大于双精度值,具体取决于舍入模式。当转换回 时double,我们可以检查它是否小于或大于原始值。然后,如果 的值方向float不正确,我们就float从转换后的数字沿原始数字的方向查看下一个数字。