在 C 中乘除整数以避免溢出的正确方法是什么?ticks
我想确定以(以赫兹为单位)运行的计时器需要多少个freq
才能生成delay
(以毫秒为单位)。这应该是ticks = freq * delay / 1000
。
但是,这条线对我来说看起来很危险。如果我们这样写,(freq * delay) / 1000
就会面临溢出的风险。如果我们写成freq * (delay / 1000)
,我们就会陷入浮点数——这是不必要的并且容易出错,尤其是。在微控制器上。
这样做的正确方法是什么?
您的建议:
不是浮点运算。这需要:
但你说得对,没有必要。更好的是:
只要
freq
是 1000 的倍数,就不会导致精度损失,并且至少可以避免“过早”溢出(即由于操作顺序选择不当而在较低值处发生溢出)。当然,溢出仍然是可能的,但该表达式给出了可能的最大范围,而
delay
无需求助于更大的类型。例如,如果表达式的类型为uint32_t
,则delay
最多可达 2 32 /1000,或近 72 分钟。至关重要的是,重新排序使得 的范围
delay
在任何系统中都具有确定性。它不再依赖于 的值freq
- 它将始终是 72 分钟。如果 72 分钟不够长,您甚至可以在采用较大的数据类型之前考虑较低分辨率的延迟(例如整秒)(这会降低效率并可能增加原子性问题)。长延迟很少需要毫秒精度,并且您的时钟在任何情况下都可能在该时间长度内达到毫秒精度 - 即使 TCXO 的精度通常可达 2ppm。
简单地说,想想您最多可以延迟多长时间。
如果使用 32 位无符号数(延迟的负数不太实用,因为我不知道如何产生负延迟,这会让我们回到过去)。uint32_t 的最大值为 4,294,967,295,足以延迟一小时以上。
如果您将计时器设置为每 1/1000 秒递增一次,那么 uint32_t 将足以延迟
49.7102696181
几天如果您需要更多,请在计算中使用更大的无符号整数:
((uint64_t)freq * delay) / 1000