首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >防止算术溢出

防止算术溢出
EN

Stack Overflow用户
提问于 2020-06-19 15:59:42
回答 3查看 114关注 0票数 0

我想用PIC18F14K50的模数转换器外设计算电压。结果在0-1023 (10位)之间.所以我用了这个简单的计算:

代码语言:javascript
复制
uint16_t voltage = ADC_Result * 5000 / 1023;

然而,结果是不正确的。我猜发生了算术溢出。我尝试了许多括号的组合,改变元素的顺序等等。

使用下面的代码,当ADC_Result为1023时,最好的结果是4088;这实际上离5000很远。

代码语言:javascript
复制
uint16_t voltage = ADC_Result * (5000 / 1023);

我应该怎么做才能在上述计算中得到更好的结果?请不要建议浮点数,因为它们会在MCU中造成灾难!他们使用了大量的资源,却没有任何真正的好处。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-06-19 16:05:44

您可以在中间乘法中使用更宽的类型,例如:

代码语言:javascript
复制
uint16_t voltage = (uint32_t)ADC_Result * 5000 / 1023;

编辑

如果1023的除法太慢,则可以通过将5000 / 1023更改为5005 / 1024来获得大致相等的转换,这可以为除法使用快速的位移位:

代码语言:javascript
复制
uint16_t voltage = (uint32_t)ADC_Result * 5005 >> 10;

注: 1023 * 5005 / 1024≃5000.1123

票数 2
EN

Stack Overflow用户

发布于 2020-06-19 16:06:01

对于此计算,应使用更宽的整数类型,如uint32_t

在您的例子中,1023 * 5000 == 3192 (因为实际结果5115000不适合),所以这是不正确的。5000 / 1023 == 4,这是整数除法的预期结果。将ADC_Result除以1023将导致同样的行为。

您可以将其计算到uint32_t中,然后检查它是否适合uint16_t

代码语言:javascript
复制
uint32_t result_tmp = ADC_Result * (5000 / 1023);
uint16_t result;

if (result > 0xffff) {
    // this won't fit
} else {
    result = (uint16_t) result_tmp;
}
票数 0
EN

Stack Overflow用户

发布于 2020-06-20 01:14:39

我该怎么做才能在上面的计算中得到更好的结果?

OP的代码溢出了1‘6位的数学。

为了得到一个正确和全面的结果,使用更广泛的数学和偏移量。

代码语言:javascript
复制
// uint16_t voltage = ADC_Result * 5000 / 1023;
uint16_t voltage = (ADC_Result * 5000LU + 1024u/2) / 1024u;
// or
#include <stdint.h>
...
uint16_t voltage = (ADC_Result * UINT32_C(5000) + 1024u/2) / 1024u;

L in 5000LU至少提供了32位的数学运算.

使用U进行可能更简单/更快的数学计算,并且在ADC_Result不是负的情况下进行更简单的舍入。

+ 1024/2的效果是从圆到最近而不是截断。

考虑到A/D转换器的通常特性,使用1024而不是1023进行正确的缩放。副作用: 1024的速度更快,是2的力量.

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62474149

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档