c++ 为什么在C Arduino中将整数乘以一个数字会给出错误的答案?[duplicate]

9cbw7uwe  于 2022-11-27  发布在  其他
关注(0)|答案(2)|浏览(151)

此问题在此处已有答案

Arduino Uno is making errors when doing calculations(2个答案)
Arduino computing error - giving negative values when it shouldn't(2个答案)
5天前关闭。
我试图计算电位计的Angular 值,所以我需要乘以180,然后除以量程。这样做后,我注意到得到的数字不是我期望的数字,所以我开始调试,只乘以180,并意识到输出不是预期的那样。**以下是输出奇怪读数的简单代码:*`

#define POTENTIOMETER_PIN A0
int val;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

  // put your main code here, to run repeatedly:
void loop()
{
  val = analogRead(POTENTIOMETER_PIN);
  Serial.println(val*180);
  delay(250);
}

`
预期值在(0到1023)*180之间,而不是串行监视器输出值,例如:18932年-18752年-18572年-18392年-18392年

lbsnaicq

lbsnaicq1#

看一看您的用例中的map()函数
https://www.arduino.cc/reference/en/language/functions/math/map/

int val = 0;  // assign at declaration

void loop()
{
  val = analogRead(POTENTIOMETER_PIN);  // read value
  val = map(val, 0, 1023, 0, 180);      // convert into 180 range
  Serial.println(val);                  // display value
}

在内部,这使用了比不起眼的int更大的类型,使用了long,它(可能)是32位而不是16位
从上述文档中

long map(long x, long in_min, long in_max, long out_min, long out_max) {
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

这种方法更适合您,并且可以正确地进行数学运算的原因是,16位数字不包含足够的乘法精度,而map()在进行数学运算时,内部使用32位数字来表示值!
具体来说,如果在您依赖16位数学运算的逻辑过程中,值超出了~32768的范围,它将 * 回绕 * 并变为负值!
这被称为Integer Overflow,维基百科文章链接了一个使用汽车里程表的很好的演示
第100,000英里 * 溢出 * 并绕回为1,因为第一个数字没有空间,因此被截断

一些人更详细地阐述了Arduino上的int文档中的观点,特别是因为尽管存在很多争论(包括 * 为什么 * Arduino选择提供int),但通常好的做法是始终准确地指定您所追求的类型,如uint32_t,而不是依赖int,后者在不同的设备目标上可能有不同的大小,这令人沮丧
https://www.arduino.cc/reference/en/language/variables/data-types/int/
在Arduino Uno(和其他基于ATmega的板卡)上,int存储一个16位(2字节)的值,其范围为-32,768到32,767(最小值为-2^15,最大值为(2^15)- 1)。
在基于Arduino Due和SAMD的开发板上(如MKR 1000和Zero),int存储一个32位(4字节)的值,其范围为-2,147,483,648到2,147,483,647(最小值为-2^31,最大值为(2^31)- 1)。

b4lqfgs4

b4lqfgs42#

您的编译器似乎将int定义为16位有符号数。
因此,存在32767到-32768的限制。
您超出了此值,因此值“环绕”。
请尝试将代码更改为使用“long”而不是“int”。

相关问题