android – Fixed-Point-Math – 从float安全转换到总是产生相同的结果吗?

我正在使用libfixmath进行模拟,同时需要在两个设备(iOS /
Android)上进行,并且非常准确.

模拟需要输入一些初始浮点参数.我想知道,如果使用浮点数然后将它们转换为fix16_t是安全的(函数来自库),或者我是否需要使用fix16_t值来提供模拟?

因此,由于浮点不准确,两个不同的设备是否有可能使用相同的输入来计算下面的函数?

typedef int32_t fix16_t;
static const fix16_t fix16_one = 0x00010000; /*!< fix16_t value of 1 */

static inline fix16_t fix16_from_float(float a)
{
    float temp = a * fix16_one; 

    // rounding
    temp += (temp >= 0) ? 0.5f : -0.5f;
    return (fix16_t)temp;
}

最佳答案 假如说:

>两台机器都使用IEEE-754单精度浮点表示浮动,和
>价值a是“合理的”

转换应该是可移植的,可能的例外情况是a的绝对值略小于0.5×2-16.

将(二进制)浮点数乘以2的幂(在这种情况下为216)是精确的,只要它不会导致浮点溢出(或在负幂为2的情况下下溢).每个浮点实现都应以完全相同的方式处理该乘法.

C标准要求从浮点数转换为整数类型以截断为0,因此舍入策略是正确的.

在几乎所有情况下,向temp添加0.5都会产生正确的结果.

对于临时的中间值,结果将是精确的.

如果temp大于223,则添加将没有效果,但没有要舍入的分数,因此只要在回退到整数时没有溢出,最终结果将是可预测的.

如果temp小于1.0,则总和将是不精确的,因为指数将增加.然后应该加法以产生正确的结果.在这里,唯一感兴趣的情况是截断的和可能是0或1;如果temp不接近0.5,则总和不能为1.0,截断的总和必须为0.如果temp至少为0.5,则总和必须至少为1.0,截断的总和必须为1.

但如果温度略低于0.5,则总和的舍入可能很大.特别是,如果temp恰好是0.5-2-25,则存在歧义.总和的结果将是1.0-2-25,但是这个值不能精确表示为IEEE-754单精度浮点数.此外,误差项恰好是ULP的一半.所以结果需要四舍五入,这将遵循实现的舍入模式.

IEEE-754的默认舍入模式是“banker’s rounding”,其中正好一半的值的四舍五入是两个可能性中的任何一个具有0作为其低位比特.这将有利于将0.5-2-25 0.5舍入到1.0,这将产生不正确的整数截断1.但是,给定的实现可能使用不同的舍入模式,可能是因为它已使用std::fesetround设置.

所有上述内容同样适用于负值.

点赞