Challenge - Casting Double to Byte

My code below is a quick sketch I whipped up to allow me to use the serial monitor to set a servo to a given position. It works perfectly if I input values from 0 to 90, but it messes up if I input a value of at least 100 for the servo angle. After inputting 100, it says the angle is actually 99. If I input a 180, it outputs a 179. Each time, it's off by 1.

I narrowed the error to the point where the program casts the 100.00 (as a double) to a byte. This value of 100.00 is returned from the pow() function. On the flip side, the program correctly casts 10.00 to 10 and 1.00 to 1. Check out the screenshot attached.

NOTE: If you want to test this out yourself, the serial input data frame format is: ,123 where the comma is the start of frame delimiter, 1 is the hundred's place of the angle, 2 is the ten's place, and 3 is the one's place of the angle (i.e. 90 degrees is ",090"). Also, make sure the serial monitor is in "No line ending" mode.

ANOTHER NOTE: Robin2, I have already read your SerialInputBasics tutorial and my question is not about how to serial data, just why the casting is returning the incorrect value. It is a great tutorial, though! :slight_smile:

#include <Servo.h>

int lol = 90;
Servo hi;

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

  hi.attach(52);
  hi.write(90);
}

void loop()
{
  serialStuff();
}

void serialStuff()
{
  byte trash = 0;
  char data[] = {0, 0, 0};
  byte packetSize = 4; //includes comma at start of frame
  byte i = 0;
  byte angle = 0;

  if (Serial.available() >= packetSize)
  {
    trash = Serial.read();
    if (trash == ',')
    {
      while (i < (packetSize - 1))
      {
        data[i] = Serial.read();
        i = i + 1;
      }
    }

    i = 0;

    while ( i < (packetSize - 1))
    {
      angle = angle + ((data[i] - 48) * pow(10, ((packetSize - 2) - i)));
      
      Serial.print(pow(10, ((packetSize - 2) - i)));
      Serial.print(" casted to byte is: ");
      Serial.println((byte)pow(10, ((packetSize - 2) - i)));
      
      i = i + 1;
    }

    hi.write(angle);
  }

  return;
}

I know a good workaround so that I can skip using the pow() function entirely, but I'm curious as to why casting it's returned value is sometimes incorrect.

Any thoughts?

Avoid using pow() if you can, as it uses logarithms and suffers from various inaccuracies and round off errors. For example, instead of "2" it will usually return something like 1.9999, which truncates to "1".

jremington:
Avoid using pow() if you can, as it uses logarithms and suffers from various inaccuracies and round off errors. For example, instead of "2" it will usually return something like 1.9999.

Ahh, ok. Do you think rounding is the culprit here?

[Edit] Actually, I forgot...it IS returning the correct value, but the casting doesn't.

Truncation is the culprit.

I'll bet that "100.00" as printed is not equal to the float variable returned by pow().

Cool. Nice to know.

Thanks!