【发布时间】:2016-05-05 22:20:50
【问题描述】:
注意 这是一个理论问题。我对我的实际代码的性能感到满意。我只是好奇是否有替代方案。
有没有一个技巧可以用一个整数变量值对一个常数值(它本身是 2 的整数幂)进行整数除法,而不必使用实际的除法运算?
// The fixed value of the numerator
#define SIGNAL_PULSE_COUNT 0x4000UL
// The division that could use a neat trick.
uint32_t signalToReferenceRatio(uint32_t referenceCount)
{
// Promote the numerator to a 64 bit value, shift it left by 32 so
// the result has an adequate number of bits of precision, and divide
// by the numerator.
return (uint32_t)((((uint64_t)SIGNAL_PULSE_COUNT) << 32) / referenceCount);
}
我找到了几个(很多)关于除以常数的技巧的参考资料,包括整数和浮点数。例如,What's the fastest way to divide an integer by 3? 问题有很多很好的答案,包括对其他学术和社区资料的引用。
鉴于分子是恒定的,并且它是 2 的整数幂,是否有一个巧妙的技巧可以用来代替实际的 64 位除法?某种按位运算(移位、AND、XOR、那种东西)或类似的?
我不希望任何精度损失(由于整数舍入可能超过半位)大于进行实际除法的损失,因为仪器的精度取决于此测量的精度。
“让编译器决定”不是答案,因为我想知道有没有技巧。
额外的上下文信息
我正在开发一个 16 位数据、24 位指令字微控制器的驱动程序。驱动程序对外围模块进行一些魔术,以获得固定数量的信号频率脉冲的参考频率的脉冲计数。所需结果是信号脉冲与参考脉冲的比率,表示为无符号 32 位值。该函数的算法由我正在为其开发驱动程序的设备的制造商定义,并进一步处理结果以获得浮点现实世界值,但这超出了本问题的范围。
我使用的微控制器有一个数字信号处理器,它有许多我可以使用的除法运算,如果有必要我不害怕这样做。除了将汇编指令放在一起以使其工作之外,这种方法还需要克服一些小挑战,例如 DSP 用于在 BLDC 驱动程序 ISR 中执行 PID 功能,但没有什么是我无法管理的。
【问题讨论】:
-
即使有一个,我也不会使用 C 而是汇编。这样您就可以确定不会执行任何优化,并且可以按照您的意愿对所有内容进行编程。
-
没有 16 位 ARM 内核!并将优化留给您的编译器。不要做过早的优化。生成的汇编代码是什么?并且:优化除法,但随后使用浮点声音......不一致。
-
你希望这个技巧能做什么?它应该给你什么是正常除法没有的?
-
“诀窍”可能是使用编译时常量,然后确保函数是内联的。然后编译器将能够根据具体情况进行最佳优化。
-
一个“trick”的属性归结为
1/referenceCount并组成由SIGNAL_PULSE_COUNT缩放的分数,OP 可以容忍一个小错误,直接power_of_2/x太慢了。假设SIGNAL_PULSE_COUNT == 0不是问题。给这篇文章一些时间。
标签: c optimization theory integer-arithmetic