Search code examples
javafloating-pointdistance

Is calculating the distance between two floating-point numbers symmetrical?


For a Java program, I wrote a method to calculate the distance between two floating-point numbers. It is very important that this method works symmetrically for the input order. Currently I'm using the method:

double distanceBetween(double a, double b) {
    return Math.abs(a - b);  // I assume that a-b = -(b-a)
}

But I'm not sure if this is always symmetrical, or if I should change the code to:

double distanceBetween(double a, double b) {
    if (a > b) return a - b;
    else return b - a;
}

So my question is, is

Math.abs(a - b) == Math.abs(b - a)

guaranteed to be always true for all values for a and b? Or is it possible that in some cases (due to the use of floating-point math) the result isn't exactly the same?


Solution

  • Is calculating the distance between two floating-point numbers symmetrical?

    Yes in Java’s native floating-point operations, no in other languages when asymmetric rounding methods are used, and possibly no in Java’s BigDecimal when asymmetric rounding methods are used (see end).

    IEEE 754-2019 5.1 says:

    … Unless otherwise specified, each of the computational operations specified by this standard that returns a numeric result shall be performed as if it first produced an intermediate result correct to infinite precision and with unbounded range, and then rounded that intermediate result, if necessary, to fit in the destination’s format (see 4 and 7)…

    Subtraction and absolute value are operations specified by the standard that return a numeric result, and there is no “otherwise specified” statement for them. IEEE 754 floating-point formats are symmetric with regard to sign; for any representable number x, −x is also representable. So, with any symmetric rounding method, if ab is rounded to some number x, then ba is rounded to −x.

    IEEE 754 specifies asymmetric rounding modes, such as round-toward-infinity (round upward). With an asymmetric rounding mode, ab will not always be rounded symmetrically to ba. For example, with a hypothetical two-digit decimal floating-point, 14 - 1.7 would produce a result of 13 (14 − 1.7 = 12.3, and that is rounded upward to 13), but 1.7 − 14 would produce −12 (1.7 − 14 = −12.3, and that is rounded upward to −12).

    However, Java does not use asymmetric rounding modes for its native floating-point operations (The Java Virtual Machine Specification, Java SE 18 Edition, 2022-02-23, section 2.8, page 20).

    Taking the absolute value never rounds because its mathematical result is always representable, so it is not a factor in the analysis.

    Java’s BigDecimal has some support for asymmetric rounding methods, but it is not clear to me whether these are built into operations (i.e., will be performed automatically during a subtraction) or must be manually applied. If the former is the cae, then ab and ba will not always produce symmetric results in BigDecimal.