Fixed "near" comparison is one approach, but is has its own issues.
Basically, the amount of the precision of a floating point number is not a fixed value, which means that different sizes of numbers have different amounts of error. A number to the power of 100 for example, has a much larger error range than a number to the power of -100. Your simplistic solution is a good "first" approach, but it won't work well outside of a narrow range of values.
In addition, error on a number should be tracked through the computation. If I add 20 numbers together, the error range isn't constant, and if I multiply 20 numbers together, the error range doesn't grow linearly.
The real answer to all of these questions is "measurement error analysis", but it's a non-useful answer because in effect, you are asking a question about measurement error analysis.
Assuming you believe the inputted value is 100% correct, then you can automatically know the error of the error of the floating point representation. This error is basically the distance to the next valid floating point number.
The first bit (bit 0) of a floating point number is the sign bit (0 = positive, 1 = negative). This has nothing to do with distance, so we skip it.
The next 8 bits (bit 1-9) is the exponent of the number, in 2's complement form. This provides a range of -128 to 127 for the exponent.
The remaining 23 bits is the fractional portion of the number's mantissa. Every non-zero number in binary eventually has a 1, and the 23 bits represent every bit after that initial 1. For you to become familiar with these numbers, you need to realize that these are bits representing fractions, so the first bit is 1/2, the next 1/4, and so on.
This means that the 23 bit is 1/8388608 of the value of the "1" bit, and the error is (+ or -)(1/8388608)^(your float's power).
Adding two numbers together is (A + B), but as we have errors, it is (A + err(a) + B + err(b)), this results in the answer's error growing (A + B) with err(a)+err(b). Note that err(a) and err(b) are "plus or minus" values, so the error range is "the smallest err(a) + the smallest err(b) to the largest err(a) + the largest err(b)).
Likewise, when multiplying you are really multiplying (A + err(a))(B + err(b)), leading to an error of B(err(a)) + A(err(b)) + (err(a))(err(b)). Again, this will have to be done with each err(x) being plus or minus, so and then capturing the output of the error in maximum upper and lower bounds). Similar computations can be done for division (A + err(a))/(B + err(b)).
So, if you want true error tracking through your computations, it won't be enough to just limit you errors to the inputted values, you will also have to follow them through each computation the system makes.
True error analysis is quite laborious, so much of the world assumes the errors won't accumulate to a significant value sufficient to alter the result. When you get 'to the next layer' of the field, you start to apply statistical tools to the error, often applying a statistical distribution to the initial error of a measurement and then tracking the error distribution fields through the computations.
Minitest
library (gem) is an interesting point of comparison. It has bothassert_in_delta
(checks the value has an absolute error less than "delta") andassert_in_epsilon
(checks that the value has a relative error less than the "epsilon"). Interestingly, both have have a default value for the allowable error, despite it only really making sense for the epsilon.