有什么聪明的方法可以解决这个问题吗?
uint32_t a = 16637510;
uint32_t b = 45627362;
uint32_t c = 0;
c = a * 100000 / b //overflows
c = (a * 100/b)*1000 //gives 36000
我需要得到结果c = 36463或更好36464.并且需要快速,非浮动操作。 CPU是stm32f4
更新
接受的答案是将100000转换为100000ULL(64位),但正如@PeterJ建议的那样(并删除了他的答案)使用stm32f4 FPU比64次分割操作更快
Timer t;
int i;
t.start();
for(i = 1; i <= 100000; ++i) c = a * 100000ULL / b;
t.stop();
printf("64\ttakes %f seconds, du is %d\n", t.read(), c);
t.reset();
t.start();
for(i = 1; i <= 100000; ++i) c = (uint32_t)((float)a * 100000.0f / (float)b);
t.stop();
printf("float\ttakes %f seconds, du is %d\n", t.read(), c);
t.reset();
64需要0.086669秒,du是57333
float需要0.017779秒,du是57333
答案 0 :(得分:1)
这个怎么样?
c = a * 100000ULL / b; // gives 36463
有关gcc为此操作生成的程序集以及溢出的原始c = a * 100000 / b
,请参阅https://godbolt.org/g/aemCyw。请注意,__aeabi_uldivmod
代替__aeabi_uidiv
。
答案 1 :(得分:0)
当64位数学成本很高时,有时32位的近似解决方案可能会明显加快。取决于处理器/编译器。
让我们看看只使用32位数学可以做什么。
b == 100000 == 0x186A0
让我们假设它是固定的 - 一个17位的数字。
a == 16637510 == 0x00FDDE46
,但OP表示它在+/- 1000之内。所以它是一个24位数字。 b
是一个26位数字。有了这些限制,最终商将始终位于36464邻域(16位数)
我们可以扩展产品操作数a,b
以使用大约a
的16个有效位和b
的16个大部分有效位,而不会失去太多意义。然后我们有一个16位* 16位产品,不会溢出32位数学。
我们可以利用b
只有12个有效位,使代码最多使用产品中24位a
的20(32-12)个最高有效位。
中间产品是41位,因此我们需要将乘法缩减至少9位。
#define SCALE_A 4
#define SCALE_M 5
// Insure SCALE_A + SCALE_M >= 9 to avoid overflow
// Perhaps other scales like SCALE_A 8, SCALE_M 1 will be faster.
uint32_t scale(uint32_t a, uint32_t b) {
uint32_t product = (a >> SCALE_A)*(100000 >> SCALE_M);
uint32_t c = product/(b >> (SCALE_A + SCALE_M));
return c;
}
如果OP更快/更好?也许。只需另一种方法来考虑。我会留给用户在线进行性能分析。