Два значения с плавающей запятой не добавляются и не печатаются на ESP-WROOM-32.
У меня есть плата Olimex ESP32-PoE, на которой есть ESP-WROOM-32.
Я только что обнаружил странное поведение при печати чисел с плавающей запятой на доске.
Скетч
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
float a=34567891.234;
float b=2.3456;
a++;
Serial.print(a+b, 4);
Serial.println("");
delay(1000);
}
Скетч чрезвычайно прост: я хочу сложить два числа с плавающей запятой, одно большое, а другое маленькое, чтобы напечатать результат их сложения до 4 знаков.
Вывод
на последовательной консоли в Arduino IDE
34567896.0000
34567896.0000
34567896.0000
34567896.0000
34567896.0000
34567896.0000
34567896.0000
34567896.0000
34567896.0000
34567896.0000
34567896.0000
34567896.0000
34567896.0000
Каждый раз, когда я увеличиваю float a
с помощью a++
, я ожидаю, что он увеличится на единицу и распечатаю результат, но вывод выше полностью отключен.
Без приращения
void loop() {
// put your main code here, to run repeatedly:
float a=34567891.234;
float b=2.3456;
Serial.print(a+b, 4);
Serial.println("");
delay(1000);
}
выход
34567896.0000
34567896.0000
34567896.0000
Тот же результат.
Это специфичная плата или Serial.print
не поддерживает float?
@Shan-Desai, 👍1
Обсуждение2 ответа
Лучший ответ:
Как уже говорилось в комментариях и ответе Дэйва X, число с плавающей точкой ограничено.
разрешение. Это разрешение задается константой FLT_EPSILON
,
что представляет собой разницу между 1 и наименьшим числом с плавающей запятой, превышающим 1.
В любой системе, соответствующей стандарту IEEE 754, FLT_EPSILON
равен 2-23,
или около 1.19e-7. Это означает, что в интервале
[1, 2], действительные числа, которые можно точно представить с помощью чисел с плавающей запятой.
кратны FLT_EPSILON
. Разрешение, однако, ухудшается по мере того, как
вы рассматриваете большие числа. В интервале [2, 4] это вдвое больше
как грубо. В пределах [4, 8] оно в четыре раза грубее и так далее:
interval resolution
------------------------------------------
1 – 2 2^-23 ≈ 1.19e-7 (FLT_EPSILON)
2 – 4 2^-22
...
2^23 – 2^24 1
2^24 – 2^25 2
2^25 – 2^26 4
...
Ваше число a
чуть больше 225. В рамках этого
дальность, числовое разрешение (также известное как «ulp»: единица измерения на последнем месте)
равно 4 (последняя строка в таблице выше). Таким образом, плавающие числа в этом диапазоне могут
представляют собой только точные кратные 4. Когда ты пишешь
double a=34567891.234;
компилятор заменяет это ближайшим числом с плавающей точкой, которое оказывается 34567892. То же самое для b, но в этом случае ошибка округления мала. и несущественный (около -1.1e-7). Когда ты пишешь
a++;
вы заменяете a
плавающей точкой, ближайшей к a+1
, что
сам по себе является a
. Так что инструкция не имеет никакого эффекта. Когда ты это сделаешь
Serial.print(a+b, 4);
вы вычисляете число с плавающей запятой, ближайшее к 34567892+2,3456, что 34567896.
Вместо этого double
имеет разрешение DBL_EPSILON
, которое
2-52 или около 2,22e-16. Это дает вам некоторую точность
запас, но имейте в виду, что Arduino на базе AVR на самом деле не поддерживают
удваивается и воспринимает ключевое слово double
как синоним float
. Этот
может стать проблемой только в том случае, если вам когда-нибудь придется переместить свой код в более
традиционный Arduino.
Я не знал о синониме AVR с двойным плавающим числом. Спасибо., @Dave X
Попробуйте двойные значения вместо чисел с плавающей запятой.
Вашему начальному значению 34567891,234 требуется 35-битная точность для отслеживания десятичных знаков, но у чисел с плавающей точкой точность только 24 бита. Таким образом, чтобы иметь достаточную точность для отслеживания разницы между 34567891.234
и 34567891.234+1
, вам необходимо хранилище с более высокой точностью.
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
double a=34567891.234;
double b=2.3456;
a++;
Serial.print(a+b, 4);
Serial.println("");
delay(1000);
}
- Float печатается только 2 десятичных знака после запятой
- Отправка числа с плавающей запятой из python в arduino
- Как прочитать входящие ШЕСТНАДЦАТИРИЧНОЕ значение из serial метод read ()?
- Ошибка чтения флэш-памяти, 1000
- Как платы Arduino устраняют необходимость нажимать кнопки для прошивки?
- Нужен ESP32 для использования 3 последовательных портов
- Не могу подключиться к плате ESP32 через последовательный порт
- Почему Serial.write() работает, а Serial.print() нет?
Попробуйте двойку. 34567891.234 требует 35 бит точности для хранения десятичных знаков, но числа с плавающей запятой имеют только 23., @Dave X
Есть аналогичный вопрос, но это меня еще больше смущает: https://stackoverflow.com/questions/8561393/is-using-increment-operator-on-floats-bad-style, @Jot