Very strange behavior from floor()

Note floor is a double function that takes a double value and produces a double result. There is a floorf function that takes a float value and produces a float result.

On your PC, double is 64-bits (1 sign bit, 11 exponent bits, 52 mantissa bits, 1 implied mantissa bit), while float is 32-bits (1 sign bit, 8 exponent bits, 23 mantissa bits, 1 implied mantissa bit). On the Arduino, doubles are 32-bits instead of 64-bit. This doesn't meet the ISO C standard, which requires double to be at least 64-bits, but it is common in various miroprocessors that are emulating floating point, to save space by not implementing 64-bit.

The C language was developed on a machine (PDP-11) where it was more convenient to do floating point arithmetic in 64-bit, so the C language is biased towards using double (constants are double by default), but now you can have expressions calculated in single precision if the compiler prefers if both sides are single precision.

#include <math.h>
#include <stdio.h>

float x = 8.3199996;

int main (void)
{
  printf ("floor  ((%f * 1000)/1000) = %f\n", x, floor  (x * 1000.) / 1000.);
  printf ("floorf ((%f * 1000)/1000) = %f\n", x, (double)(floorf (x * 1000.f) / 1000.f));
  return 0;
}

However, because most machines do floating point in binary instead of decimal, you will get round off errors if you do the multiply by 1000, floor, and then divide by 1000.