定点数学 - 从浮动安全转换到总是产生相同的结果吗?

时间:2016-01-13 14:59:38

标签: android c++ ios floating-point fixed-point

我使用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;
}

1 个答案:

答案 0 :(得分:2)

假设:

  • 两台机器都使用float的IEEE-754单精度浮点表示,

  • a是“合理的”

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

将(二进制)浮点数乘以2的幂(在本例中为2 16 )是精确的,前提是它不会导致浮点溢出(或者在下溢的情况下下溢)负面力量2)。每个浮点实现都应该以完全相同的方式处理乘法。

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

temp中添加0.5将在几乎所有情况下产生正确的结果。

对于temp的中间值,结果将是准确的。

如果temp大于2 23 ,则添加将无效,但没有要舍入的分数,因此只要有最终结果就是可预测的当回流到整数时没有溢出。

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

但如果temp略小于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设置。

以上所有内容同样适用于负值。