Thank you for all the feedback! I think I've incorporated everything. If this all looks good, I'd be happy to work on some of the other math functions too. (Hopefully I'll be able to break my C habits!)
I ran into an interesting bug / edge case withTESTEQUALS_FLOAT by the way:
An unsigned fixed point 0.0 and a double 0.0 fail the equality check.
So, part of the macro tests for inequality with lhs < (rhs - epsilon). The result of rhs - epsilon is static_cast back into its raw type for the actual comparison. Now, if rhs - epsilon is negative and we cast into an unsigned type, then this behavior is undefined. On x86, the value underflows so the inequality condition is met. On arm, the value is set to 0. (Which was why I didn't catch the failing test).
Here's an example case that fails on x86:
TESTEQUALS_FLOAT((FixedPoint<uint32_t, 16>::zero()), 0.0, 1e-4);
I think it should be possible to resolve this by checking for lhs + epsilon < rhs instead. But floats are cursed and aren't associative, so this could cause unexpected behavior down the line. I've chosen to just omit the 0 case for now.