Is the strange problem I'm having to do with comparing floats? I have a timer interrupt that controls a stepper motor, on an UNO board. In the interrupt handler it checks the speed of the motor and compares it to the target speed. This allows the motor to accelerate to the target speed in a non-blocking way.

This is the relevant part of the interrupt handler:

ISR(TIMER1_COMPA_vect){
    if (targetSpeed &gt; 0 || motorSpeed &gt; 0){
        // leading edge of the step cycle
        if (leadingEdge){
            digitalWrite(STEP_PIN, HIGH);
            stepNumber++;
            // check speed and adjust if necesary
            if (motorSpeed &lt; targetSpeed){
                motorSpeed += speedIncrement;
            }
            else if (motorSpeed &gt; targetSpeed){
                motorSpeed -= speedIncrement;
            }

            leadingEdge = false;
        }
        // trailing edge
        else{
            digitalWrite(STEP_PIN, LOW);
            leadingEdge = true;
        }
    }
    OCR1A = minInteruptsPerStep + (minInteruptsPerStep * (1 - motorSpeed));
}


In the loop() I have a function that checks the state of motorSpeed to control other functions

if (motorSpeed == targetSpeed) {
    motorState = RUNNING;
} else if (motorSpeed &lt; targetSpeed) {
    motorState  = ACCELERATING;
} else if (motorSpeed &gt; targetSpeed) {
    motorState  = DECELERATING;
}


motorSpeed and targetSpeed are floats and range from 0-1, in steps of 0.1 speedIncrement is 0.001 As far I can see that should ramp the speed up until motorSpeed == targetSpeed, in 100 steps. And this mostly what happens. The speed gets to targetSpeed and motorState switches from ACCELERATING to RUNNING, as expected.. mostly. The problem is that it occasionally starts flipping between the three states, for no reason I can see--there is nothing that should modify the value of motorSpeed outside the interrupt handler, so once it stops accelerating it should be stable.

Is this because I'm using and comparing floats? Should I scale the speed variables up and use an int or even a byte?
You already know, from previous answers, why the comparison doesn't give
you the result you expect: you assumed that any multiple of 0.1 is also
a multiple of 0.001, which is true for real numbers but nor for floats.

To fix the issue, it has been suggested to you to allow for some
fussiness in the comparison. I would suggest a different approach: keep
your comparisons as they are, and instead change the way the speed is
updated in the ISR:



if (motorSpeed &lt; targetSpeed) {
    motorSpeed = min(motorSpeed + speedIncrement, targetSpeed);
}
else if (motorSpeed &gt; targetSpeed) {
    motorSpeed = max(motorSpeed - speedIncrement, targetSpeed);
}


With this logic, motorSpeed will always end up being exactly equal
to targetSpeed, irrespective of whether the speed change is a multiple
of the increment or not.

A common misconception about floating point numbers has it that they are
not exact. Truth is, most floating point calculations involve rounding
errors, but the floating point numbers themselves are exact numbers,
if not the numbers you expect¹. Then, when you do the assignment

motorSpeed = targetSpeed;


which the code above ends up doing at some point, you can test

if (motorSpeed == targetSpeed) ...


and it will be true.

¹ When you write “0.1” in the source code, you get the float which is
closest to 0.1, which happens to be 0.100000001490116119384765625
exactly.