ESP8266 "ovf" 做小双数时

ESP8266 "ovf" when doing small double maths

我正在使用基于 ESP8266 wifi 芯片和 Arduino C 框架的 Wemos D1 来做一些简单的小数学运算。 据我所知,双精度是可用的,所以我正在使用它——最大为 1.8*10^103。 但是当我尝试计算一个大约 5*10^8 的数字时,我得到了一个 ovf。 有什么想法吗?

void setup(){
  Serial.begin(9600);
  while(!Serial);
  Serial.println("Hit any key to start math");
  double te = 6800;
  double res = te * te;
  Serial.println(res);
  te = 68000;
  res = te * te;
  Serial.println(res);
   te = 680000;
   res = te * te;
  Serial.println(res);
}

void loop(){
}

打印

46240000.00
ovf
ovf

Arduino 确实支持 4 字节双精度数据类型。并且您的代码确实产生了一个有效的双精度值,该值不会溢出(ovf)。

您看到的问题与 Arduino 实现 Serial.print() 函数的方式有关,它几乎就像一个支持浮点的半生不熟的 hack,不如 vprintf() that is available in avr-libc. You can see the source code here 可靠对于大于 4294967040.0 或小于 -4294967040.0 的任何值,打印 ovf。我认为 ESP8266 Arduino Core 已经解决了这个问题,而不是继承 Arduino 的丑陋实现 Serial.print(),但显然不是。

幸运的是,ESP8266 Arduino Core 确实有一个 Serial.printf() 方法可以提供更好的浮点渲染。此代码将显示您的号码确实是 double 数据类型的有效号码。

void setup(){
  Serial.begin(9600);
  while(!Serial);

  double te = 68000;
  double res = te * te;
  Serial.println(res);  //this will produce 'ovf'
  Serial.printf("Result=%f\n", res);  //this will produce correct 4624000000.000000
}

请注意,Serial.printf() 是 ESP8266 的特定实现,以支持标准库中的全浮点 vprintf()。它不适用于标准 Arduino 开发板。

对于 Arduino 板,有一种方法可以使用继承自 vprintf()sprintf() 来打印正确的浮点数,并在代码编译过程中对链接器选项进行一些改动。我有一个博客 post Do you know Arduino - sprintf() and floating point 谈论如何做到这一点。