3

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? i.e. 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

asked Oct 21, 2016 at 12:25

2 Answers 2

9

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.

answered Oct 21, 2016 at 12:29
Sign up to request clarification or add additional context in comments.

2 Comments

If using 1.8 or later, java.lang.Math.nextDown(1.0f) or, if using the usually better choice of double instead of float, java.lang.Math.nextDown(1.0)
I know double would be better, but I am running out of memory, so I want to figure out if float suffices for my purposes. Anyway, thanks for the comment, because use Java 1.8 and thus can use the respective function.
2

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.

e.g. 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
answered Oct 21, 2016 at 13:03

1 Comment

@Bathsheba hehe, you seem so surprised. ;)

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.