【发布时间】:2016-10-05 11:55:05
【问题描述】:
我想知道做比例计算最快的方法,就是y = x * a / b,这里所有的值都是32位的,无符号的,a和b是固定的(初始化一次,然后不更改)但在编译时未知。结果保证不会溢出(即使中间乘法可能需要 64 位)。编程语言无关紧要,但 Java 最适合我的情况。它需要尽可能快(纳秒很重要)。我目前使用:
int result = (int) ((long) x * a / b);
但是除法很慢。我知道Perform integer division using multiplication,所以最好是一个类型的公式:
int result = (int) (((long) x * factor) >>> shift);
其中factor 和shift 可以从a 和b 计算(计算可能很慢)。
我试图简单地替换原始公式的除法部分,但它不起作用,因为两次乘法的结果不适合 64 位:
// init
int shift = 63 - Integer.numberOfLeadingZeros(b);
int factor = ((1L << shift) / b) + 1;
...
// actual calculation
int result = (int) ((long) x * a * factor) >>> shift);
在我的情况下,结果实际上不必完全准确(减一即可)。
【问题讨论】:
-
我现在有一个(部分)解决方案:
shift = 16; factor = ((long) a << 16) / b + 1;- 但它只适用于某些值范围。如果可能的话,最好有一个适用于所有无符号 32 位值的通用解决方案。 -
鉴于您知道具有不变除数的整数除法,尚不清楚您卡在哪里。鉴于
a, b, x都是uint32_t,计算无符号uint64_t乘积x*a,然后对其应用带有常数除数b的64 位除法。如果b是编译时常量,只需使用除法运算符并让编译器对其进行优化。最后,将uint64_t商转换回uint32_t(根据问题中的规范,这可以保证构造成功,无需额外测试)。 -
@njuffa 不幸的是,这些值在编译时是未知的。我一直在努力寻找一个优雅的解决方案,保证边缘情况的行为(a、b 和 x 的高值)。我想我现在已经解决了。
标签: java optimization bit-manipulation division multiplication