Wrong value assigned to byte from float. What am I missing?

Hi,
I am performing a conversion from a float value, to a sequence of bytes, so I can drive a 4 character display.
Here is the snip of code that give me the error...
The function should convert a number like 12.34 into bytes. In this case bcd4, bcd3, bcd2, bcd1.

// Not Sure Why???

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

void loop() {
  float dispval=112.34;
  SetBCD(dispval);
   delay(500); 
}

void SetBCD( float conv ){
  byte bcd4, bcd3, bcd2, bcd1;
  byte shift; 
  conv=conv/100; // remove any extra above 99.999
  shift = conv; // Save the integer part
  bcd4 = conv = 10.0*(conv-shift); //remove and save
  bcd3 = conv = 10.0*(conv-bcd4); //remove save
  bcd2 = conv = 10.0*(conv-bcd3); //remove save
  bcd1 = conv = 10.0*(conv-bcd2); //remove save
  
Serial.print("::");
Serial.print(bcd4);
Serial.print("-");
Serial.print(bcd3);
Serial.print("-");
Serial.print(bcd2);
Serial.print("-");
Serial.println(bcd1);  

}

Here is what I am getting from the serial monitor: I would expect ::1-2-3-4, not 1,2,3,3.

::1-2-3-3
::1-2-3-3

Thanks for taking time to look.

Rich

that is something you can anaylse by serial printing all intermediate calculations step by step
best regards Stefan

I would do this like this :

void SetBCD( float conv ){
  int bcdall = int (conv * 100.0);  // this cuts all beyond 2 spaces behind the .
  byte bcd[4];
  uint8_t i = 4;
  while (i) {
    i--;
    bcd[i] = bcdall % 10; // extract the digit
    bcdall = bcdall / 10;  // slide to the right (decimals)
  }
  Serial.println();
  for (uint8_t i = 0; i <4; i++) {
    Serial.print(bcd[i], DEC);
    Serial.print(",");
  }
}
#define N_BCD   4
byte bcd [N_BCD];

void
getBcd (
    float val,
    byte  bcd [] )
{
    char s [20];
    dtostrf (val, 6, 2, s);

    bcd [0] = s [1] - '0';
    bcd [1] = s [2] - '0';
    bcd [2] = s [4] - '0';
    bcd [3] = s [5] - '0';
}

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

    float f = 112.34;

    getBcd (f, bcd);
    for (byte n = 0; n < N_BCD; n++)
        Serial.print (bcd [n]);
    Serial.println ("");
}

void loop() {
}

StefanL38:
that is something you can anaylse by serial printing all intermediate calculations step by step
best regards Stefan

Yes, I have done that. Changed code etc. Works as expected until the last conversion. Basically I have 0.40 in the float when multiplied by 10 and assigned to the byte, is loaded with 3, not 4 as it should be. I assume this is some kind of Arduio math problem, like 4 is internally stored as 3.99999999999 and truncated on assignment to the byte.
Thanks for the suggestion.

One way to avoid truncation problems is to add 0.5 to the float before truncating.

  conv = conv / 100; // remove any extra above 99.999
  shift = conv; // Save the integer part
  bcd4 = 0.5 + (conv = 10.0 * (conv - shift)); //remove and save
  bcd3 = 0.5 + (conv = 10.0 * (conv - bcd4)); //remove save
  bcd2 = 0.5 + (conv = 10.0 * (conv - bcd3)); //remove save
  bcd1 = 0.5 + (conv = 10.0 * (conv - bcd2)); //remove save

Output:

::1-2-3-4

Deva_Rishi and gcjr, thanks for the code suggestions. I will have to study them a bit. The bit of code I uploaded was simplified to show my frustration. Having the result in array is useful to me. Ultimately the values (BCD) are placed onto outputs 4,5,6, and 7, (chip D0 to D3) while the position BCD[n] is a chip latch enable on outputs 8,9,10,11 or like 2^n..

Thanks,

Rich

Qsilverrdc:
The function should convert a number like 12.34 into bytes. In this case bcd4, bcd3, bcd2, bcd1.

Here is what I am getting from the serial monitor: I would expect ::1-2-3-4, not 1,2,3,3.

12.34 does not have an exact representation in a binary floating point variable. So when you put "12.34" into your sketch, the C compiler is converting it to the closest possible value that will fit in a float, something like 12.3399999 .

I'd suggest rounding that final digit. Rounding each digit is not the correct thing to do.

Thanks all, I have the routine working now!