ESP8266 "OVF" при выполнении небольших двойных математике - PullRequest
1 голос
/ 03 апреля 2020

Я использую Wemos D1 на основе Wi-Fi-чипа ESP8266 с платформой Arduino C, чтобы выполнить простую небольшую математику. Насколько я могу судить, доступна двойная точность, поэтому я использую ее - максимум около 1,8 * 10 ^ 103. Но я получаю ovf, когда пытаюсь вычислить число около 5 * 10 ^ 8. Есть идеи, пожалуйста?

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

1 Ответ

1 голос
/ 04 апреля 2020

Arduino поддерживает 4-байтовый двойной тип данных. и ваш код действительно выдает допустимое двойное значение, которое не является переполнением (ovf).

Проблема, которую вы видите, связана с тем, как Arduino реализует функцию Serial.print(), которая почти наполовину приготовлена ​​для поддержки плавающей запятой и не так надежна, как vprintf () доступно в avr-lib c. Вы можете увидеть исходный код здесь , который печатает ovf для всего, что больше 4294967040.0 или меньше, чем -4294967040.0. Я подумал, что ESP8266 Arduino Core исправил это, вместо того, чтобы наследовать уродливую реализацию Arduino Serial.print(), но, очевидно, нет.

К счастью, ESP8266 Arduino Core имеет метод Serial.printf(), который обеспечивает лучший рендеринг с плавающей запятой. Этот код покажет, что ваш номер действительно является действительным числом для двойного типа данных.

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, определяемая c для поддержки полной плавающей запятой vprintf() в стандарте библиотека. Он недоступен для стандартных плат Arduino.

Для плат Arduino есть способ использовать sprintf(), который наследуется от vprintf(), для печати правильной плавающей запятой с некоторыми изменениями параметров компоновщика в процессе компиляции кода. У меня есть запись в блоге Знаете ли вы Arduino - sprintf () и плавающая точка говорят о том, как это сделать.

...