gpt4 book ai didi

What is the correct way to determine `ticks` from clock `freq` while avoiding overflow in C on a microcontroller?(在避免微控制器上C语言溢出的情况下,从时钟`freq`确定`ticks`的正确方法是什么?)

转载 作者:bug小助手 更新时间:2023-10-24 20:48:16 38 4
gpt4 key购买 nike



What is the correct way to multiply and divide ints in C to avoid overflow? I want to determine how many ticks of a timer running at freq (in Hz) will take to make a delay (in ms). This should be ticks = freq * delay / 1000.

在C中乘除整数以避免溢出的正确方法是什么?我想确定以频率(以赫兹为单位)运行的计时器延迟(以毫秒为单位)将花费多少滴答声。这应该是TICKS=freq*Delay/1000。


But, that line looks dangerous to me. If we write (freq * delay) / 1000 we run the risk of overflow. If instead we write freq * (delay / 1000), we will get into floats - which are unnecessary and error prone, esp. on a microcontroller.

但是,在我看来,这条线很危险。如果我们写入(freq*Delay)/1000,我们就有溢出的风险。相反,如果我们编写freq*(Delay/1000),我们将进入浮点数-这是不必要的,而且容易出错,例如。在微控制器上。


What is the correct way to do this?

正确的做法是什么?




Code is running on a Cortex M4 ARM microcontroller. Ticks are from SysTick timer. All vars are uint32_t or volatile uint32_t.

代码在Cortex M4 ARM微控制器上运行。滴答来自SysTick Timer。所有变量都是uint32_t或易失性uint32_t。


更多回答

On a uC why not create a tick timer, that runs at say 100 hz, use that interrupt to increment a tick count? Or did I misunderstand you?

在UC上,为什么不创建一个滴答计时器,以100赫兹的速度运行,使用该中断来增加滴答计数?还是我误解了你?

You need to consider freq and delay maximum ranges and use appropriate int size for the multiplication. For example, if freq and delay are both 16-bit, You cast them to 32-bit ints for multiplication. If You are able to have constant freq, you can use it to Your advantage to simplify the computation.

您需要考虑频率和延迟最大范围,并使用适当的整数大小进行乘法。例如,如果Freq和Delay都是16位的,则将它们强制转换为32位整数进行乘法。如果你能有恒定的频率,你可以利用它来简化计算。

Choose the more appropriate integer range for the presumed maximum count, then use casting to force calculation. I.e. unsigned int ticks = (unsigned int)((unsigned long long)freq * (unsigned long long)delay / 1000ULL). This example should fit your calculation.

为假定的最大计数选择更合适的整数范围,然后使用强制转换来强制计算。即UNSIGNED INT TICKS=(UNSIGNED INT)((UNSIGNED LONG LONG)freq*(UNSIGNED LONG LONG)Delay/1000ULL)。这个例子应该符合你的计算。

freq/1000*delay + freq%1000*delay/1000

频率/1000*延迟+频率%1000*延迟/1000

Can you please, at least, if not showing actual code, specify how, or some context in which you are geting those ticks. Are you in an embedded context? are you running some high level operating system (one with an interrupt based clock) or are you running an Operating System with system calls to get the time? What is the type you are using to hold those timestamps?

如果没有显示实际的代码,请至少说明一下如何获取这些标记,或者是在什么上下文中获取这些标记。您是否处于嵌入式环境中?你是在运行某个高级操作系统(带有基于中断的时钟),还是在运行一个通过系统调用来获取时间的操作系统?您使用什么类型来保存这些时间戳?

优秀答案推荐

Your suggested:

您的建议:


freq * (delay / 1000)

Is not a floating point operation. That would require:

不是浮点运算。这将需要:


freq * (delay / 1000.0)

But you are correct that it is not necessary. Far better would be:

但你说得对,这是没有必要的。更好的办法是:


(freq / 1000) * delay

So long as freq is a multiple of 1000, that will result in no loss of precision, and avoids at least a "premature" overflow (i.e. an overflow that occurs at lower values due to a poor choice of operation order).

只要freq是1000的倍数,就不会导致精度损失,并且至少可以避免“过早”溢出(即,由于操作顺序选择不当而在较低值时发生的溢出)。


An overflow of course remains possible, but this expression gives the maximum range possible for delay without resorting to a larger type. For example if the expression is of type uint32_t, delay can be up to 232/1000, or nearly 72 minutes.

当然,溢出仍然是可能的,但此表达式给出了在不求助于更大类型的情况下延迟的最大可能范围。例如,如果表达式的类型为uint32_t,则延迟可能高达232/1000,即近72分钟。


Critically, the reordering enables the range of delay to be deterministic across any system. It is no longer dependent on the value of freq - it will always be 72 minutes.

关键的是,重新排序使延迟范围在任何系统上都是确定的。它不再依赖于freq的值-它将始终是72分钟。


If 72 minutes is not long enough, you might even then consider a lower resolution delay (whole seconds for example) before resorting a larger data type (which will be less efficient and may add atomicity issues). Long delays seldom require millisecond precision, and your clock may not be millisecond precise over that length of time in any case - even TCXO's are accurate to typically 2ppm, giving a potential 1ms drift after 500 seconds.

如果72分钟不够长,那么您甚至可以考虑较低的分辨率延迟(例如整秒),然后再使用较大的数据类型(这将降低效率,并可能增加原子性问题)。较长的延迟很少需要毫秒精度,而且您的时钟在任何情况下都可能不会在该时间长度上精确到毫秒-即使TCXO的精度通常也达到2ppm,在500秒后可能会出现1ms的漂移。



Simply, think how long maximum delay you can have.

简单地说,想想你可以有多长时间的最大延迟。


If using 32bit unsigned number (negative numbers for delay are not very practical because I do not know how to have a negative delay which would take us back in time). The maximum uint32_t is 4,294,967,295 which is enough for more than one hour delay.

如果使用32位无符号数字(延迟的负数不是很实际,因为我不知道如何有一个负的延迟,这将使我们回到过去)。最大uint32_t为4,294,967,295,足以满足一个多小时的延迟。


If you set your timer to increment every 1/1000 sec then uint32_t will be enough to delay 49.7102696181 days

如果您将计时器设置为每1/1000秒递增一次,则uint32_t将足以延迟49.7102696181天


If you need more use a larger unsigned integer in your calculations: ((uint64_t)freq * delay) / 1000

如果需要更多,请在计算中使用更大的无符号整数:((Uint64_T)freq*Delay)/1000




to determine how many ticks of a timer running at freq (in Hz) will take to make a delay (in ms). This should be ticks = freq * delay / 1000.




  • Use sufficiently width enough math, perhaps uint64_t to prevent multiplication overflow.

    使用足够宽的数学运算,或许可以使用uint64_t来防止乘法溢出。



  • Consider unsigned math in this case to simplify rounding.

    在本例中考虑无符号数学,以简化四舍五入。



  • Physical quantities often deserve a rounded answer. Round by adding 1/2 the denominator before division.

    物理量往往需要一个全面的答案。在除法前加上1/2的分母进行舍入。



  • Clearly identify physical units.

    清楚地识别物理单元。



  • Avoid naked magic numbers.

    避免赤裸裸的魔术数字。




uint32_t ticks(uint32_t freq /* Hz */, uint32_t delay /* ms */) {
#define ms_PER_s 1000
return (uint32_t) (( (uint64_t)freq*delay + ms_PER_s/2) / ms_PER_s);
}

更多回答

This can give incorrect results, because you may get overflow in the intermediate calcs.

这可能会给出不正确的结果,因为您可能会在中间计算中获得溢出。

@SRobertJames where? BTW unsigned numbers do not overflow

@SRobertJames在哪里?顺便说一句,无符号数字不会溢出

It is true that 2^32 milliseconds is >49 days, but that is not what the question is about. The intermediate multiply is the issue. Reordering helps make it deterministic (i..e. not dependent on the variable), but an overflow will still occur at ~72 minutes. Which is probably fine in most cases.

2^32毫秒确实大于49天,但这不是问题的核心。中间乘法是问题所在。重新排序有助于使其具有确定性(即,不依赖于变量),但大约72分钟仍会发生溢出。这在大多数情况下可能是好的。

"unsigned numbers do not overflow" is somewhat semantic sophistry. I would call it overflow, and it is largely understood. Even if you correctly refer to it as a modulo-n error, it is still an error.

“无符号数字不溢出”在某种程度上是语义上的诡辩。我会称之为溢出,这在很大程度上是可以理解的。即使您正确地将其称为模n错误,它仍然是一个错误。

38 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com