我使用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;
}
答案 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
设置。
以上所有内容同样适用于负值。