2

When printing with one decimal place, Arduino's Serial.println() rounds numbers like 123.89 to “123.9”. Is there any way to change the rounding mode? For some reasons I want the value to be rounded towards zero (i.e., truncated) to one decimal place, like 123.89 → “123.8”.

here is the code

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

}

void loop() 
{
float A = analogRead(A0);
A = (A/1023)*5.0;
Serial.print("A = ");
Serial.println(A,3);
float B = A*10;
Serial.print("A * 10 = ");  
Serial.println(B,1);
delay(1000);
}

the output is

A = 2.473
A * 10 = 24.7
A = 2.488
A * 10 = 24.9
A = 2.517
A * 10 = 25.2
A = 2.527
A * 10 = 25.3
A = 2.507
A * 10 = 25.1

instead I want the output to be like this

A = 2.473
A * 10 = 24.7
A = 2.488
A * 10 = 24.8
A = 2.517
A * 10 = 25.1
A = 2.527
A * 10 = 25.2
A = 2.507
A * 10 = 25.0

is it possible ?

  • 1
    We can't tell you what you're doing wrong if we don't know what you're doing. – Ignacio Vazquez-Abrams Jun 14 '18 at 16:20
  • This is not the serial monitor. It is the serial output statements in your sketch, or more likely the floating point format itself. You might perhaps consider using a double instead of a float. But it's also unclear that the value being printed is not already the most accurate decimal approximation of the value internally stored. Without your code this is unanswerable. – Chris Stratton Jun 14 '18 at 16:24
  • 3
    So you want the output to be truncated instead of rounded? 2.59 as 2.5 instead of 2.6? – Craig Jun 14 '18 at 17:15
  • 1
    What you are describing is by no means a value that is "exact up to one decimal place" Your major problem here is that you've failed to really articulate that you want a value that is intentionally inexact. Do you have any actual justification for distorting your data like this??? – Chris Stratton Jun 14 '18 at 17:54
  • 1
    Note that most decimal numbers are not exactly representable as floats. For example, if you type float x = 23.40;, the compiler rounds that number to the nearest representable float, which happens to have the exact value 23.3999996185302734375. If you truncate this to one decimal place, then 23.40 ends up being printed as “23.3”! – Edgar Bonet Jun 14 '18 at 20:53
8

A cheap trick to round a number to one decimal place (in "chop-off mode") is to multiply it by 10, convert it to an integer, and divide by 10.0f again:

float myVal = 123.89f;
myVal = (long)(myVal * 10) / 10.0f;
// = ((long)1238.9) / 10.0f
// = 1238 / 10.0f
// = 123.8

You can then print this modified number to the serial monitor.

This method can also be generalized to other precisions. For 2 decimal places, we just have to multiply by 10^2 (100) and divide by 10^2. A macro would be:

#define TRUNCATE(val, numDecimalPlaces) \
    (float)(((long)((double)(val) * pow(10, (numDecimalPlaces) * 1.0f))) / (pow(10, (numDecimalPlaces)* 1.0f)))

Note: You don't have to actually dynamically compute pow(10, numDecimalPlaces), you can also create macros for each decimal precision from 1 to x and simply precompute that value (100, 1000, 10000, ..).

The same can also be achieved by using the standard library function trunc from math.h:

#define TRUNCATE_TO_ONE(val) \
    (trunc((val) * 10.0f) / 10.0f)

See http://www.cplusplus.com/reference/cmath/trunc/.

Here's a small sketch in which it is demonstrated:

#include <Arduino.h>

#define TRUNCATE(val, numDecimalPlaces) \
    (float)(((long)((double)(val) * pow(10, (numDecimalPlaces) * 1.0f))) / (pow(10, (numDecimalPlaces)* 1.0f)))

#define TRUNCATE_TO_ONE(val) \
    (trunc((val) * 10.0f) / 10.0f)


void printValueFormatted(float value, int numDecimalPlaces) {
    //format correctly
    char buf[20];
    char* res = dtostrf(value, sizeof(buf)-1, numDecimalPlaces, buf);

    //skip over empty chars
    while(*res == ' ')
        res++;

    //print buffer
    Serial.println(res);
}


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

void loop(void)
{
    float myVal = 123.8978f;
    printValueFormatted(myVal, 4);
    printValueFormatted(TRUNCATE(myVal, 1), 1);
    printValueFormatted(TRUNCATE(myVal, 2), 2);
    printValueFormatted(TRUNCATE(myVal, 3), 3);
    printValueFormatted(TRUNCATE(myVal, 1), 4);
    printValueFormatted(TRUNCATE(myVal, 2), 4);
    printValueFormatted(TRUNCATE(myVal, 3), 4);
    delay(1000);
}

Prints

123.8978
123.8
123.89
123.897
123.8000
123.8900
123.8970
  • I am having some problems when I am using this piece of code.. I am using serial print to print some analog values from the A0 and A1 pin of an arduino uno and dividing the values from each other to get a ratio. Eg: A = A0 and B = A1 after that C = A/B and printing values C * 100 on the serial monitor. Everything is working perfectly fine until I made the value of B very low. Applying this code giving me negative values of the ratio and without it it is giving perfect values which is rounded to the nearest. Is there anything else to overcome this problem? – Peouse Dutta Jun 15 '18 at 10:31
  • 1
    @PeouseDutta int is a 2-byte integer with a range of about -32K to +32K. Might be too small for you if you suddenly multiply by 100. I updated the code to convert it to long instead. – Maximilian Gerhardt Jun 15 '18 at 11:30
  • 1
    Note that pow() is expensive if you don't have an FPU. – Edgar Bonet Jun 15 '18 at 12:03
  • 1
    I addressed this above. The pow is only needed to compute 10^x, just precompute it. – Maximilian Gerhardt Jun 15 '18 at 12:13
  • 1
    I did a small test and it turns out that a call to pow() with compile-time constant arguments gets optimized out by gcc into a constant. So you should be fine with pow(). Check the generated assembly if in doubt. – Edgar Bonet Jun 15 '18 at 12:27
0

Use the given [function] for your problem. This function works on a pre-defined [algorithm].

int roundTowardZero(float number, int decimal_place) {
    float round_number = round(number);
    if(round_number > number) round_number = round_number - 1;
    float deci = (number - round_number) * pow(10, decimal_place);
    float round_decimal = round(deci);
    if(round_decimal > deci) round_decimal = round_decimal - 1;
    round_decimal = round_decimal / pow(10, decimal_place);
    total_number = round_number + round_decimal;
    return total_number;
}

Place this function above int setup()

like:

int roundTowardZero( ... ) {
    ...
}
void setup() {
    ...
}
void loop() {
    ...
}

Function syntex is like this : roundTowardZero([Enter a Decimal Value], [Enter Round Place Value]) Example :roundTowardZero(123.89, 1) //Output : 123.8

Please comment below is you find any problem or face any error.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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