Я использую этот кусок кода в стандартных тестах для сравнения, если исход из 2-х различных расчетов являются одинаковыми, за исключением плавающей запятой математических ошибок.
Он работает, рассматривая двоичное представление числа с плавающей запятой. Большая часть осложнений связана с тем, что знак чисел с плавающей запятой не является дополнением к двум. После компенсации за это в основном сводится к простому вычитанию, чтобы получить разницу в ULP (поясняется в комментарии ниже).
/**
* Compare two floating points for equality within a margin of error.
*
* This can be used to compensate for inequality caused by accumulated
* floating point math errors.
*
* The error margin is specified in ULPs (units of least precision).
* A one-ULP difference means there are no representable floats in between.
* E.g. 0f and 1.4e-45f are one ULP apart. So are -6.1340704f and -6.13407f.
* Depending on the number of calculations involved, typically a margin of
* 1-5 ULPs should be enough.
*
* @param expected The expected value.
* @param actual The actual value.
* @param maxUlps The maximum difference in ULPs.
*/
public static void compareFloatEquals(float expected, float actual, int maxUlps) {
int expectedBits = Float.floatToIntBits(expected) < 0 ? 0x80000000 - Float.floatToIntBits(expected) : Float.floatToIntBits(expected);
int actualBits = Float.floatToIntBits(actual) < 0 ? 0x80000000 - Float.floatToIntBits(actual) : Float.floatToIntBits(actual);
int difference = expectedBits > actualBits ? expectedBits - actualBits : actualBits - expectedBits;
return !Float.isNaN(expected) && !Float.isNaN(actual) && difference <= maxUlps;
}
Вот версия для double
точности поплавки:
/**
* Compare two double precision floats for equality within a margin of error.
*
* @param expected The expected value.
* @param actual The actual value.
* @param maxUlps The maximum difference in ULPs.
* @see Utils#compareFloatEquals(float, float, int)
*/
public static void compareDoubleEquals(double expected, double actual, long maxUlps) {
long expectedBits = Double.doubleToLongBits(expected) < 0 ? 0x8000000000000000L - Double.doubleToLongBits(expected) : Double.doubleToLongBits(expected);
long actualBits = Double.doubleToLongBits(actual) < 0 ? 0x8000000000000000L - Double.doubleToLongBits(actual) : Double.doubleToLongBits(actual);
long difference = expectedBits > actualBits ? expectedBits - actualBits : actualBits - expectedBits;
return !Double.isNaN(expected) && !Double.isNaN(actual) && difference <= maxUlps;
}
Заявить float как: 'float a = 1.2f;' и удваивается как 'double d = 1.2d;' Также в вашем if-statement: 'if (c == 3.6f)' –
В дополнение к @bobah ' Ответ, я рекомендую посмотреть на функцию 'Math.ulp()'. – aeracode