Search code examples
javafloating-pointaverage

Mathematical properties of the computed average value of two floating point numbers?


I compute the average value of two floating point numbers x and y. (I use the type double in Java) Because when I do max-min-searches with it I really want to make sure that this operation will work consistently (from a mathematical point of view). I worry about what happens if x and y are equal or almost equal?

I compute the average value with:

double average = (x + y) / 2.0;

Assuming the sum of (x + y) is not overflowing, I have three questions about the mathematical properties of this average value:

  1. if (x < y) and there is space between x and y for at least one number (that can be represented in the floating point system), can I then safely assume that:

average > x && average < y; is guaranteed to be always true?

  1. if (x < y) but they are as close together as possible (so that there is no space for a number between x and y that can be represented in the floating point system), can I then safely assume that:

average == x || average == y; is guaranteed to be always true?

  1. if (x == y) can I then safely assume that:

average == x; is guaranteed to be always true?

One more thing I wonder about is if it might be better do compute the average with: double average = x / 2.0 + y / 2.0; I know that in floating point math the distributive law is not equivalent in general but I don't know which one I should use. Is there a recommended way in general?


Solution

    1. if (x < y) and there is space between x and y for at least one number (that can be represented in the floating point system), can I then safely assume that:

    average > x && average < y; is guaranteed to be always true?

    Yes except for overflow. If x+y overflows (produces an infinity), then double average = (x + y) / 2.0; produces an infinity. Otherwise, consider that x+y equals (x/2 + y/2)•2, and x/2+y/2 must be closer to a number between x and y than it is to either s or y. Therefore adding x/2 + y/2 with floating-point arithmetic would produce that number (or one of the others between x and y if there are more than one), so adding x and y must produce twice that number (as long as it does not overflow). Then (x+y)/2 gives us that number.

    (As long as the exponent remains within range, any 2*a+2*b must produce the same result as 2*(a+b), because all of the significand arithmetic remains identical—all roundings occur at the same place relative to the significand. This is true only for powers of two. For example, it is also true that 4*a+4*b produces the same result as 4*(a+b). But it is not always true that 3*a+3*b produces the same result as 3*(a+b).)

    1. if (x < y) but they are as close together as possible (so that there is no space for a number between x and y that can be represented in the floating point system), can I then safely assume that:

    average == x || average == y; is guaranteed to be always true?

    Yes except for overflow. As above, adding x/2 and y/2 would produce either x or y, so x+y produces 2•x or 2•y.

    1. if (x == y) can I then safely assume that:

    average == x; is guaranteed to be always true?

    Yes except for overflow.

    One more thing I wonder about is if it might be better do compute the average with: double average = x / 2.0 + y / 2.0;

    This will not make any difference unless there is overflow in x+y or underflow in x/2 or y/2.