优化问题:整数加倍

Optimization concern : int to double

本文关键字:整数 问题 优化      更新时间:2023-10-16

我有一些程序中使用的这两种插值方法......

__forceinline double InterpolateDouble(double dOldVal, double dOldMin, double dOldMax, double dNewMin, double dNewMax) 
{ 
    return (((dOldVal - dOldMin) * (dNewMax - dNewMin)) / (dOldMax - dOldMin)) + dNewMin; 
}
__forceinline int InterpolateInteger(int nOldVal, int nOldMin, int nOldMax, int nNewMin, int nNewMax) 
{ 
    return (int)InterpolateDouble((double)nOldVal, (double)nOldMin, (double)nOldMax, (double)nNewMin, (double)nNewMax); 
}

该方法InterpolateInteger()简单地调用InterpolateDouble()方法来保持一定的分数精度。从整数到双精度的转换是否是一个问题,有没有办法仅使用整数(无强制转换)获得准确的结果?

除法前乘法时存在溢出的风险,就像您的代码在这里所做的那样。 除了代码中可能的乘法中间计算之外,还必须检查输入的可能值,以确定 int 类型是否始终足以包含计算。 截断将在整数除法时发生,但如果你想要整数结果,这是意料之中的。从 CPU 的角度来看,从 int 到 double 的转换是微不足道的,因为在计算之前,整数的前面有一个前缀 0。

这不是你应该担心的从 int 到 double 的转换。这是工作完成后从 double 到 int 的转换(截断)。考虑将 [0, 500] 插值到 [0, 1]。在这种情况下,一旦您执行插值双精度,对于 500 个输入,数字将是 1 个输出,对于输入 0-499,数字将小于 1。因此,0-499 输入在截断后将导致 0 输出,500 将导致 1。

如果您追求最大优化并且插值点是固定的,则可以使用以下整数表达式:

(dOldVal * dNewDelta + dNewMin * dOldDelta - dOldMin * dNewDelta) / dOldDelta

其形式为(A * X + B) / C,其中ABC是三个预先计算的整数常数。这将产生精确的整数答案。

或者,使用具有双精度预计算系数的A * X + B,但需要仔细调整舍入策略。

另一种可能性是使用 2 的幂重新缩放和舍入AB系数,给出形式的快速无除整数公式

(A * X + B) >> p

(舍入策略也很微妙)。