1

I want to round a decimal number (x), but I need to do it differently depending on how it is. If it has integer significant digits, we round to the nearest integer, and if not, we round to the first significant digit. So the following would happen with these example numbers: 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... (The numbers could have more or less decimal places than in the examples).

To implement this, I have created a function (type) in which we check if the most significant digit is of type integer or decimal. This function returns this characteristic of the number in the form of a "string". So if the most significant digit is an integer we just use the "round()" function. However, I don't know how to round a number to the first significant digit (roundto_fsd() function). Does anyone know of any function capable of doing this or any method to do it?

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() {}
0

1 Answer 1

1

First of all, let me clarify that there is nothing “decimal” in a float: a float is a binary (not decimal) floating point number. The Serial.println() function does a binary-to-decimal conversion for the purpose of representing the number as human-readable text. If you want a specific number of decimal digits after the radix point, you should ask Serial.println() to provide them. This is done by passing this number as a second parameter:

Serial.println(sqrt(2));    // prints "1.41" (2 decimals by default)
Serial.println(sqrt(2), 0); // prints "1"
Serial.println(sqrt(2), 5); // prints "1.41421"

Now the question is: how to compute the number of required digits after the radix point? This depends on how big the float is. If it is smaller than 1 but larger or equal to 0.1, you want just one digit. If it is ten times smaller than that, you want to digits, and so on:

numbers      digits
───────────────────
[1, +∞)        0
[0.1, 1)       1
[0.01, 0.1)    2
[0.001, 0.01)  3

I suggest repeatedly multiplying your float by 10 until it gets ≥ 1, and count the number of times you had to do so:

/* How many decimal places to print. */
int decimal_places(float x)
{
    int i = 0;
    while (x < 1) {
        x *= 10;
        i++;
    }
    return i;
}

You would use this function like this:

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

Note that there is a small issue with this approach. If you try to print 0.97, decimal_places() will say you need one decimal, and Serial.println() will print “1.0”. If you would rather have it print “1”, then change the loop condition within decimal_places() to:

while (x < 0.95)

Caveat: All this assumes that the numbers you want to print are all strictly larger than zero. Otherwise decimal_places() would have an infinite loop.

2
  • Thank you! Is using the "while(x<0.95)" condition because Serial.print() rounds?
    – Libegria
    Commented May 21, 2022 at 21:24
  • @Libegria: It's because Serial.print() rounds to nearest, meaning 0.97 would be rounded up to 1.0, but 0.93 would be rounded down to 0.9. Commented May 21, 2022 at 21:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.