Search code examples
javaprimitive-types

How to compare correctly long and float primitives?


For some reason I need to compare two primitives: long and float.

Can I use following code for this?

long a = 111L;
float b = 111.1f

if (a > b) {
  ...
}

I know, that float and float can be compared to some accuracy with using epsilon value and etc.

But how can I perform comparison for my case more correctly?

Thanks to all.


Solution

  • You can wrap both of them in BigDecimal and them compare them:

    long a = 111L;
    float b = 111.1f;
    BigDecimal first = new BigDecimal(a);
    BigDecimal second = new BigDecimal(b, MathContext.DECIMAL32);
    if (first.compareTo(second) > 0) { ... }
    

    In order to understand why we're interested to have both of the operands under the same type, let's dig a bit into JLS 5.6.2 Binary Numeric Promotion:

    When an operator applies binary numeric promotion to a pair of operands, each of which must denote a value that is convertible to a numeric type, the following rules apply, in order:

    1. If any operand is of a reference type, it is subjected to unboxing conversion (§5.1.8).

    2. Widening primitive conversion (§5.1.2) is applied to convert either or both operands as specified by the following rules:

      • If either operand is of type double, the other is converted to double.

      • Otherwise, if either operand is of type float, the other is converted to float.

      • Otherwise, if either operand is of type long, the other is converted to long.

      • Otherwise, both operands are converted to type int.

    With this we can conclude that for the comparison a > b the long operand will be implicitly promoted to float. This, however, can end up with loss of precision, as stated in JLS 5.1.2 Widening primitive conversion:

    A widening conversion of an int or a long value to float, or of a long value to double, may result in loss of precision - that is, the result may lose some of the least significant bits of the value. In this case, the resulting floating-point value will be a correctly rounded version of the integer value, using IEEE 754 round-to-nearest mode (§4.2.4).