Weird Math.max() behaviour. Math.max(0f, Float.MIN_VALUE) is Float.MIN_VALUE??

I’m trying to detect the bounds of my Polygon class, and I found a very weird bug. [icode]Math.max(0f, Float.MIN_VALUE)[/icode] is returning [icode]Float.MIN_VALUE[/icode]?? I found this while debugging the code in IntelliJ IDE.

http://puu.sh/dxeNm/cef48e02a1.png

That’s very very much weird for me. What I did was nothing, initially I set the values of min variables to Float.MAX_VALUE and the max variables to Float.MIN_VALUE. Comparing then with a vector is returning this weird behaviour. Any pointers?

(By the way, the same code worked fine until today, I wrote that one day ago)

As always, questions like these are best answered by the API: https://docs.oracle.com/javase/8/docs/api/java/lang/Float.html#MIN_VALUE

[quote]MIN_VALUE
public static final float MIN_VALUE
A constant holding the smallest positive nonzero value of type float, 2-149. It is equal to the hexadecimal floating-point literal 0x0.000002P-126f and also equal to Float.intBitsToFloat(0x1).
[/quote]
Or at the very least, try throwing together a little test program:


public class Test {
	public static void main (String... args){
		System.out.println(Float.MIN_VALUE); //prints 1.4E-45
		System.out.println(0 < Float.MIN_VALUE); //prints true
	}
}

Basically, Float.MIN_VALUE does not contain the smallest, most negative number imaginable. It contains the smallest decimal that can be represented as a float. This number is a tiny bit greater than 0.

In other words, this is definitely not a bug. This is exactly the intended behavior.

You might be looking for the most negative number imaginable, which is Float.NEGATIVE_INFINITY. Placeholder values like that have a bad code smell, imho, but that’s outside the bounds of this question.

one tricky pitfall. on top of that, Integer.MIN_VALUE is the largest negative number (if i remember correctly) just to confuse us.

Technically, Float.NEGATIVE_INFINITY is the largest (in terms of absolute value) negative number.


public class Test {
	public static void main (String... args){
		System.out.println(Float.NEGATIVE_INFINITY < Integer.MIN_VALUE); //prints true
	}
}

… i’m wondering, since i ran into that too some day - i use [icode]-Float.MAX_VALUE[/icode] now, is this the correct way ?

It really depends on what you’re trying to do. If you can guarantee that any values you’re using are compatible with your use of -Float.MAX_VALUE, then that’s fine- exactly the same way it would be fine to use 0 if you knew all of your numbers will be above zero.

But then again, this kind of placeholder value is a bit smelly to me. Why use a placeholder at all? Either set it to the first possible value and then do your searching from the second possible value, or if you don’t know the first value ahead of time, use a separate boolean that keeps track of whether the value has been set yet.

This is all conjecture since nobody has actually posted real use-cases though.

Edit: Strangely enough:


public class Test {
	public static void main (String... args){
		System.out.println(Float.NEGATIVE_INFINITY < -Float.MAX_VALUE); //prints true
	}
}

(I say strange in that I didn’t expect this, but this is still the intended behavior and not a bug.)

oh i use it … when computing a AABB of something. resetting min to max_value and max to -max_value, then comparing vectors.

Thanks! Using INFINITY values got it working again!

The first is very reasonable. The second isn’t…but that doesn’t matter since that situation doesn’t exist. If you’re going to compare things then a ‘first’ set of values must be known.

Yes, it is. Please back up your statements with code or concrete examples.

False.

What if I’m going to maintain the minimum of a set of data entered by the user? What should my placeholder MIN_VALUE be, before the user enters any data?

The answer is that I should set it to whatever value the user enters first- but how do I know whether the user has entered a value yet?

I would use a second variable that stores whether the user has entered any data yet. If that value is false when the user enters a value, I know I don’t have to bother comparing anything and I can just set the MIN_VALUE variable, then set the second variable to true.

The problem comes at the end: what if the user hasn’t entered any values? What should the MIN_VALUE be? That’s the whole point of using a second variable.

Hehe. Ok: Please create strawman example that someone might actually want actually do in a video game.

Answer. You could use NaNs, but that would mean using the opposite compares which might seem confusing to some. If there NaN at the end then there’s no data…but know that anyway because if the input means anything then it’s stored somewhere. Or you could use Infinities. Or you could store an invalid range.

safe and lazy way, no need to know the list-size :

public static aabb calc_bounding_box( aabb box, List<float[]> vertices )
{
  // reset box
  for( int i = 0; i < 3; i++ )
  {
    box.min[i] = Float.MAX_VALUE;
    box.max[i] = -Float.MAX_VALUE; 
  }
  
  // fit vertices
  for( float[] v : vertices )
  {
    for( int i = 0; i < 3; i++ )
    {
      if(v[i] < box.min[i]) box.min[i] = v[i];
      if(v[i] > box.max[i]) box.max[i] = v[i];
    }
  }

  // even if list is empty you get a box which can work with
  // intersection tests and whatnot, no false positives.
  return box;
}

the other way, list must have at least one element :

public static aabb calc_bounding_box( aabb box, List<float[]> vertices )
{
  // pick first vector, do or die.
  float[] first = list.get(0);
  
  // reset box
  for( int i = 0; i < 3; i++ )
  {
    box.min[i] = first[i];
    box.max[i] = first[i]; 
  }

  for( int i = 1; i < vertices.size(); i++ )
  {
    float[] v = vertices.get(i);
    for( int i = 0; i < 3; i++ )
    {
      if(v[i] < box.min[i]) box.min[i] = v[i];
      if(v[i] > box.max[i]) box.max[i] = v[i];
    }
  }
  
  return box;
}

I always do:


   float min = Integer.MAX_VALUE;
   float max = Integer.MIN_VALUE;

I haven’t come across a use case that had to deal with floats beyond the signed 32 bit integer range. :persecutioncomplex:

Why? My only argument is that it’s possible to use a secondary boolean to keep track of whether the minimum/maximum has been set yet. I then pointed out a use case where that might come in handy. Not really sure what you’re arguing against.

Or you could use a second boolean variable. The point is that there’s more than one approach. Using a special-case value is a bit of a bad code smell to me, but like I’ve also said, it all depends on the data you’re using. Some data (like I’ve already pointed out) would benefit from using a second variable. Some wouldn’t. That’s the beautiful thing about programming: there are a million valid ways to do something.

My only point is that your statement that the boolean approach is “unreasonable” isn’t true. I’m not saying no other approaches are reasonable. I’m saying using a second variable is another approach, and even the correct approach in cases like the one I mentioned.

The case I’m talking about has less to do with invalid ranges, and more to do with what you should return as the min and max when the list of data is empty.

If you can guarantee that your data will always contain values, then the job gets a lot easier. And for little games and personal projects, that’s cool. For bigger stuff, you need to think more about these kind of scenarios.

Is getting an empty list a corner case? Absolutely. But that’s where 80% of programming happens.

You could just check whether the list is empty and do the right thing (throw an Exception maybe), but that’s just using a secondary variable like I’m talking about.

My only point is that there’s more than one way to skin a cat.

Apparantly you felt the need to tell me where 80% of programming happens. For what it’s worth, I was addressing basil_'s usage of -Float.MAX_VALUE.

How to implement the behavior of aggregate functions on empty sets is rather offtopic in this thread. Typically the callsite is smart enough not to call that function in the first place, and to handle that edge case in the appropriate manner, given that there is no single correct way to handle it.

Agreed.

yea, it’s the lazy way (not testing isEmpty() on the callsite). didn’t think of using [icode]Integer.MAX_VALUE[/icode] with floats. thanks :slight_smile:

@KevinWorkman: Adding one or more variables that aren’t needed. You’re expanding the state data requirements by 50-100% and likewise for the actual code itself. More complexity is more things to write, read and maintain. There’s no upside as it bring no additional information to the table. This is so small and simple that it doesn’t make sense (generally) to write a library and looking up the existing version to copy-and-paste will take longer than just typing it out for the Nth time. And some of these Nth times you’ll do it wrong since it’s so simple you’re not even thinking about it while you’re typing.

I mentioned a use-case where a second variable comes in handy. My only point is that there are multiple ways to solve this problem. I don’t really want to bicker about it.

Chalk it up to us solving slightly different problems with slightly different requirements.