简体   繁体   中英

Java Float Precision for values between 0 and 1

I have values between 0 and 1 stored as floats. I know that delta between distinguishable floats is smaller the closer the floats are to 0. Thus, I think the precision is very high in my case (as the highest possible float is 1..). How big is my epsilon that I have to consider when comparing 2 of these floats? ie how big is the gap between 1.0f and the biggest representable float that is smaller than 1.0f? I am sorry if this question seems too broad/general but I could not find an answer :-(. Thanks

You can use the function java.lang.Math.nextAfter(float start, double direction) to help you.

Call it using, in your case, nextAfter(1.0f, 0.0) . Here we're setting the direction to be less than your starting number, so it will search "backwards". The resulting float is your answer.

Because this function also has an overload taking a double for start , be careful to use 1.0f to denote a float literal.

To get the unit of resolution for a float or double value you can use Math.ulp(x) which will give you the difference between x and the next representable value. Note: 1 has double the gap of the value immediately before 1.0

float f = 1.0f, f_1 = Math.nextDown(f);
double d = 1.0, d_1 = Math.nextDown(d);

int f_1i = Float.floatToRawIntBits(f_1);
System.out.println("f_1=" + f_1 + " f_1i=" + Integer.toHexString(f_1i) + " eps=" + Math.ulp(f_1) + " nextUp=" + Math.nextUp(f_1));

int fi = Float.floatToRawIntBits(f);
System.out.println("f=" + f + " fi=" + Integer.toHexString(fi) + " eps=" + Math.ulp(f) + " nextUp=" + Math.nextUp(f));

long d_1i = Double.doubleToRawLongBits(d_1);
System.out.println("d_1=" + d_1 + " d_1i=" + Long.toHexString(d_1i) + " eps=" + Math.ulp(d_1) + " nextUp=" + Math.nextUp(d_1));

long di = Double.doubleToRawLongBits(d);
System.out.println("d=" + d + " di=" + Long.toHexString(di) + " eps=" + Math.ulp(d) + " nextUp=" + Math.nextUp(d));

prints

f_1=0.99999994 f_1i=3f7fffff eps=5.9604645E-8 nextUp=1.0
f=1.0 fi=3f800000 eps=1.1920929E-7 nextUp=1.0000001
d_1=0.9999999999999999 d_1i=3fefffffffffffff eps=1.1102230246251565E-16 nextUp=1.0
d=1.0 di=3ff0000000000000 eps=2.220446049250313E-16 nextUp=1.0000000000000002

You can also do arithmetic on the representable values by looking at the raw integer representations.

eg Math.nextUp

public static double nextUp(double d) {
    if( Double.isNaN(d) || d == Double.POSITIVE_INFINITY)
        return d;
    else {
        d += 0.0d;
        return Double.longBitsToDouble(Double.doubleToRawLongBits(d) +
                                       ((d >= 0.0d)?+1L:-1L));
    }
}

BTW d += 0.0d turns -0.0 into +0.0

Also

System.out.println(Math.ulp(Double.NEGATIVE_INFINITY));

prints

Infinity

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM