Question

After taking a look at code using the JBox-2D engine, it is clear that float declarations are used very often:

float x = 20.0f //<-- float

FixtureDef fixDef = new FixtureDef();
fixDef.shape = shape;
fixDef.density = 0.0f; //<-- float
fixDef.friction = 0.9f; //<-- float

I have tinkered around and found that the code complies properly when it is not indicated as a float. Thus, my question is:

Why must coders define values as floats in JBox-2D even though the variable it is stored in is already declared as a float?

Was it helpful?

Solution

If a number like 0.9 is going to be assigned to a float, the result will be more accurate in some cases if it is declared as 0.9f than if it is declared as 0.9, which is a double, and then cast from double to float. Declaring it as a float literal, with the "f", will never be worse than declaring it a double and casting to float.

There would be no precision loss on assigning an int literal to a float, compared to declaring the same value as a float literal, but if everything is being done in float, it is tidier to make all literals float, not just the non-integer ones. That way, the "f" is already there if the literal is later changed from integer to fraction.

================================================================================

The source of the problem is loss of information about the literal during conversion from decimal string to double. The following is an example of how this can happen.

Suppose a decimal fraction is very slightly greater than a double that is exactly half way between two adjacent floats, and the lower of the two floats is even (last bit is a zero).

The decimal fraction is closer to the larger of the two floats, and so rounds to it on direct conversion to float. If the conversion is done via double, the rounding to double loses that information. Double to float conversion uses round-half-even which maps a double half way between two adjacent floats to the even one, in this case the smaller one.

Here is a program demonstrating this:

import java.math.BigDecimal;

public class Test {
  public static void main(String[] args) {
    BigDecimal exactValue = new BigDecimal("1.5000000596046447753906251");
    System.out.println("Exact = " + exactValue);

    double d = 1.5000000596046447753906251;
    BigDecimal dValue = new BigDecimal(d);
    System.out.println("dValue = " + dValue);

    float f1 = 1.5000000596046447753906251f;
    BigDecimal f1Value = new BigDecimal(f1);
    System.out.println("f1Value = " + f1Value);

    float f2 = (float) 1.5000000596046447753906251;
    BigDecimal f2Value = new BigDecimal(f2);
    System.out.println("f2Value = " + f2Value);

    System.out.println("f1 error = "
        + exactValue.subtract(f1Value).abs());
    System.out.println("f2 error = "
        + exactValue.subtract(f2Value).abs());
  }
}

Output:

Exact = 1.5000000596046447753906251
dValue = 1.500000059604644775390625
f1Value = 1.50000011920928955078125
f2Value = 1.5
f1 error = 5.96046447753906249E-8
f2 error = 5.96046447753906251E-8

The absolute rounding error for f1, the result of direct conversion, is less than the absolute rounding error for f2, the result of conversion via double.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top