if (fabs(a - b) <= eps)
где eps - некая маленькая величина, вообще говоря - зависящая от порядка самих чисел, поэтому более корректно
if (fabs(a - b)/ max(fabs(a) + eps, fabs(b) + eps) <= eps)
Пример задания eps:
const
FuzzFactor = 1000;
SingleResolutionEps = 1E-7 * FuzzFactor;
DoubleResolutionEps = 1E-15 * FuzzFactor;
Откуда это берётся - точность float 23 двоичных разряда или 7-8 десятичных, т.е. число имеет 7 верных десятичных цифр, поэтому меньше 1E-7 eps смысла нет делать.
Почему используется множитель FuzzFactor = 1000; - это расширение допуска, чёткого критерия его выбора нет, разработчики этой библиотеки решили так сделать, а вообще множитель можно выбирать в зависимости от желаемой погрешности в младших разрядах.
Для сравнения float и double по правилам сложения погрешностей следует использовать погрешность для менее точных float, т.е. порядка 1E-7 даже при приведении float к double, как предложил в комментарии @Grundy - ведь при этом приведении возникают дополнительные ничем не обеспеченные разряды с погрешностью в пределах всё тех же 1E-7.
Труды по точности float-арифметики: 1 2 Goldberg