【问题标题】:Frustrating Math Problem, results not as expected (EDQ)令人沮丧的数学问题,结果不如预期(EDQ)
【发布时间】:2020-11-05 04:12:17
【问题描述】:

这是我的代码,当我运行程序时,节流阀为 -18,当我进行数学运算时,我得到 77.941... 这就是我要找的。我知道这是一个 EDQ“非常愚蠢的问题”,我很可能随时都会遇到 FIF,“额头上的拳头”时刻,但我现在被困住了。仅供参考,在 Atmega 328P 上使用 Windows 10 上的 Arduino IDE 对其进行编程。

以下示例打印 -18,根据我的计算,它应该是 77.941...

  int throttle = (((800 - 270) * 100) / 680);
  Serial.println(throttle);

这是可视化代码...

  throttle = (((throttleSensor - oldMinValue) * (newMax - newMin)) / (oldMax - oldMin));

我正在尝试这样做,Convert a number range to another range, maintaining ratio

另外,我应该补充一点,当结果低于 47 时它工作正常,高于它会翻转为负数。

【问题讨论】:

  • 请尝试生成minimal, reproducible example。在不知道throttleSensor、oldMinValue、newMax、newMin、oldMax 和oldMin 是如何设置的情况下,我们最多只能猜测可能出了什么问题。
  • 这些实际数字就是我们在这个问题中要处理的。为了清楚起见,我现在进行了编辑
  • 这可能是因为ints 在您的系统中是 16 位的,并且您在 (800 - 270) * 100 = 53,000 上有溢出。带符号的 16 位整数最多只能达到 32,767。
  • Arduino 是 8 位 MCU,因此 int 仅包含 16 位。您需要改用long:int throttle = ((800 - 270) * 100L) / 680
  • 谢谢,我只是自己想到了这个问题,正在努力修复它,我会让你知道我想出了什么。

标签: c++ math arduino linear-programming


【解决方案1】:

简短的回答是,(800 - 270) * 100 = 53000。对于为计算结果分配的空间来说,这个数字太大了,整数溢出。

所以从这里更改代码...

 int throttle = (((800 - 270) * 100) / 680);

到这个...

long largeValue = 100;
int throttle = (((800 - 270) * largeValue) / 680);

解决了这个问题。数字100 或(newMax - newMin) 的值必须是“长”,否则处理器将计算错误。有人,如果需要,请纠正我,或者如果你有一个更好的答案,请发布一个更好的答案。另外,如果有人对标题有更好的建议,以便将来遇到相同问题的人更容易找到,请继续在下面推荐它。

感谢 StackOverflow 社区帮助我解决了这个问题!

【讨论】:

  • 整数除法在 C++ 中被截断,所以77.941 将使用上面的77 出来。要四舍五入到最接近的整数,请在除 ((800 - 270) * largeValue + 340) / 680 之前添加一半的分母。
  • 只需在我的评论中添加L 后缀就足够了。 L 生成 long 和 LL 生成 long long。不需要单独的变量
  • 您也可以将 100 和 680 更改为 10 和 68(或 5 和 34)以获得相同的结果。
  • @phuclv 谢谢,在这种情况下我使用它,需要是一个变量。但是谢谢你让我知道我不知道。
【解决方案2】:

作为@edgar_wideman 的回答建议您的子结果 (53000) 不适合 16 位整数 <-32768,+32767>。您可以通过位移(除以 2 的幂)来避免使用 long,如下所示:

int sh=1; // shift stuff so it fits 16 bit
int throttle = (((800 - 270) * (100>>sh)) / (680>>sh));

【讨论】:

  • 另一个好主意,是的,我是 Edgar,我最后回答了我自己的问题。无论如何感谢您的帮助!
  • @edgar_wideman heh :) 错过了你的问题......请注意右移仅适用于非负数......否则你需要使用除法......或在移位后复制 MSB像 a = (a>>1)|(a&0x8000); 而不是 a = a>>1; 就像在 ARDUINO 框架上一样0x7FFD 甚至这并不意味着不同的编译器版本以相同的方式进行
【解决方案3】:

这可能不是您正在寻找的,但有一个功能可以将值从一个范围更改为另一个范围。

int y = map(value, minOld, maxOld, minNew, maxNew);

例如:

int y = map(10, 0, 50, 0, 100); // y would be 20
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-06
  • 2011-07-19
  • 2011-05-08
  • 2012-04-03
  • 1970-01-01
  • 2012-10-25
相关资源
最近更新 更多