Округление до первой значащей цифры

Я хочу округлить десятичное число (x), но мне нужно сделать это по-разному, в зависимости от того, как оно есть. Если он содержит целочисленные значащие цифры, мы округляем до ближайшего целого числа, а если нет, то округляем до первой значащей цифры. Таким образом, с этими примерами чисел произойдет следующее: 11.871->12, 11.177->11, 37.233->37, 37.779->38, 0.578->0.6, 0.544->0.5, 0.0257->0.03, 0.0223->0.02... (Числа могут содержать больше или меньше знаков после запятой, чем в приведенных примерах).

Чтобы реализовать это, я создал функцию (type), в которой мы проверяем, имеет ли самая значащая цифра тип integer или decimal. Эта функция возвращает эту характеристику числа в виде "строки". Поэтому, если самая значащая цифра является целым числом, мы просто используем функцию "round ()". Однако я не знаю, как округлить число до первой значащей цифры (функция roundto_fsd()). Кто-нибудь знает о какой-либо функции, способной сделать это, или о каком-либо методе для этого?

float x;

char type(float number) {
  char type[8];
  if (int(number) != 0) {
    type = "integer";
  } else {
    type = "decimal";
  }
  return type;
}

float roundto_fsd(float number) {}

void setup() {
  Serial.begin(9600);
  if (!type(x).compareTo("integer")) {
    Serial.println(round(x));
  } else if (!type(x).compareTo("decimal")) {
    Serial.println(roundto_fsd(x));
  }
}

void loop() {}

, 👍1


1 ответ


1

Прежде всего, позвольте мне уточнить, что в float нет ничего “десятичного” : float - это двоичное (не десятичное) число с плавающей запятой. Функция Serial.println() выполняет двоичное преобразование в десятичное с целью представления числа в виде удобочитаемого текста. Если вам нужно определенное количество десятичных цифр после исходной точки, вы должны попросить Serial.println() предоставить их. Это делается путем передачи этого числа в качестве второго параметра:

Serial.println(sqrt(2));    // печатает "1.41" (по умолчанию 2 десятичных знака)
Serial.println(sqrt(2), 0); // печатает "1"
Serial.println(sqrt(2), 5); // печатает "1.41421"

Теперь возникает вопрос: как вычислить количество требуемых цифр после точки основания? Это зависит от того, насколько велик float. Если оно меньше 1, но больше или равно 0,1, вам нужна только одна цифра. Если оно в десять раз меньше этого, вы хотите ввести цифры и так далее:

числа        цифры
───────────────────
[1, +∞)        0
[0.1, 1)       1
[0.01, 0.1)    2
[0.001, 0.01)  3

Я предлагаю многократно умножать ваш float на 10, пока он не станет ≥ 1, и подсчитайте, сколько раз вам пришлось это делать:

/* Сколько знаков после запятой нужно напечатать. */
int decimal_places(float x)
{
    int i = 0;
    while (x < 1) {
        x *= 10;
        i++;
    }
    return i;
}

Вы могли бы использовать эту функцию следующим образом:

Serial.println(x, decimal_places(x));

Обратите внимание, что при таком подходе существует небольшая проблема. Если вы попытаетесь напечатать 0.97, decimal_places() скажет, что вам нужен один десятичный знак, а Serial.println() выведет “1.0”. Если вы предпочитаете, чтобы он печатал “1”, затем измените условие цикла в decimal_places() на:

while (x < 0.95)

Предостережение: все это предполагает, что все числа, которые вы хотите напечатать , строго больше нуля. В противном случае decimal_places() будет иметь бесконечный цикл.

,

Спасибо! Использует "while(x<0.95)" условие, потому что Serial.print() выполняет раунды?, @Libegria

@Libegria: Это потому, что Serial.print() округляется до ближайшего, то есть 0,97 будет округлено до 1,0, но 0,93 будет округлено до 0,9., @Edgar Bonet