Округление до следующего верхнего (или нижнего) 0,1

Я снимаю показания с датчика температуры. Я получаю значения с плавающей запятой с 2 десятичными знаками. Я хочу округлить их до ближайшего 0,1.

Это мой скетч:

void setup() {
  Serial.begin(115200);
}

void loop() {
  float temperature = 21.81;
  float rounded_temperature = round(temperature * 10) / 10.0;
  Serial.print("21.81 ->");
  Serial.println(rounded_temperature);
  delay(1000);

  temperature = 21.79;
  rounded_temperature = round(temperature * 10) / 10.0;
  Serial.print("21.79 ->");
  Serial.println(rounded_temperature);
  delay(1000);

  temperature = 21.77;
  rounded_temperature = round(temperature * 10) / 10.0;
  Serial.print("21.77 ->");
  Serial.println(rounded_temperature);
  delay(1000);

  temperature = 21.70;
  rounded_temperature = round(temperature * 10) / 10.0;
  Serial.print("21.70 ->");
  Serial.println(rounded_temperature);
  delay(1000);
}

Вот результат:

21.81 ->21.85
21.79 ->21.75
21.77 ->21.75
21.70 ->21.75

И это тот результат, который я бы сделал... Округлено до "0" , а не до "5".

21.81 ->21.80
21.79 ->21.80
21.77 ->21.80
21.70 ->21.70

, 👍0

Обсуждение

температура также может быть отрицательной, @sineverba

это не вопрос для arduino ... это общий вопрос программирования, @jsotola

@jsotola OP использует функцию round, которая является [частью Arduino library](https://github.com/arduino/ArduinoCore-avr/blob/6ec80154cd2ca52bce443afbbed8a1ad44d049cb/cores/arduino/Arduino.h#L96)., @Gerben


3 ответа


1

переменные с плавающей запятой не имеют числа десятичных знаков. В любом случае, они являются лишь приближением. Вместо этого именно при печати вы решаете, сколько десятичных знаков отображать.

Serial.println(temperature, 1); // Print with 1 decimal place

Или поместить его в строку:

char buf[8]; //  Место для 7 символов плюс нулевой терминатор
float val=23.81;

dtostrf(val, -7, 1, buf); //  7 символов с 1 десятичным знаком и выравниванием по левому краю (отрицательная ширина)
,

ммм... Моя проблема в том, что я отправляю эти данные через MQTT в HomeAssistant. Я хочу отправить их как "мой формат", а не с .50, @sineverba

Затем отформатируйте его в строку и отправьте ее. Используйте "dtostrf` для форматирования" char []"., @Majenko

Разве нет собственной функции для округления до .x0 вместо .50 ?, @sineverba

@sineverba Даже если вы сделаете "округление", то, скорее всего, оно не будет округлено. Как я уже сказал, поплавки - это только приближение. Единственный способ привязать его к определенному количеству цифр - это изменить его на другой формат, например текст. С помощью " dtostrf()`., @Majenko


1

Я часто храню данные с плавающей запятой, которые получаю от датчика, в целочисленном виде, чтобы сохранить требуемую десятичную точность, умножив ее на 10, прежде чем преобразовывать в целое число. Это проще и эффективнее (по сравнению со строкой или плавающей точкой) для передачи в другую систему. Это также количество датчиков, представляющих и хранящих плавающие данные (например, TMP275).

Чтобы достичь того, чего вы хотите, вот что я бы сделал:

#include <math.h>

void setup() {
  Serial.begin(115200);

  float i=21.81;
  float j=21.79;
  float k=21.77;
  float p=21.70;

  // convert to integers
  int l = (int) round(i*10);  // 218
  int m = (int) round(j*10);  // 218
  int n = (int) round(k*10);  // 218
  int o = (int) round(p*10);  // 217

  // Convert back to actual floating point for display
  Serial.println((float)l/10);  //21.80
  Serial.println((float)m/10);  //21.80
  Serial.println((float)n/10);  //21.80
  Serial.println((float)o/10);  //21.70
}
,

Хорошо.... но округление 21,81 равно 21,80, а не 21,90..., @sineverba

Я меняю его на использование "round()` вместо" ceil ()"., @hcheung


3

Используя функцию roundf ():

float rounded_temperature = roundf(temperature * 10) / 10;

,