Mathematical vectors

The same can happen for double with different values. You’re just hiding a problem that needs to be solved. The correct way to do this would be to use atan2 which has guaranteed output range. Or clamp the input value for acos. Or refactor the code to not use angles at all (many things can be done in vectors/matrices/etc. alone).

Switching to double gives you false security that it’s fixed but then it will kaboom. And it will be much worse to reproduce the bug as the precision error will get significant enough to trigger the bug after much more time than with floats.

One real example: I was using matrices for accumulating rotation (which is ‘bad’ thing) and the symptoms were pretty interesting: after some time one could notice the near clip plane slowly moved to far side… at first I thought it was something wrong in the projection matrix, but then realized it must come from some input matrices and found it. The solution was easy in my case, just renormalize it after applying incremental rotation to it. If I used doubles the bug would be triggered after longer time and would annoy players who play for few hours instead of 10mins or so and it would be much harder to reproduce for me.

inded, same as capacity overflow can happen the same with int & short…

heu… I never said otherwise, nether said that double does not need error check too…

not really related but… another area where I often have problems related to float imprecision is when using 3D Studio Max… ( I know… I know… they should have used space partitioning eh ? :wink: )

anyway you all won… I surrender… float are greaaaat ! float are fantastic ! float are magic ! ::slight_smile: :-X :-\

This is slightly different issue, integers have exact representation and the operations are also exact. So avoiding the overflow is much easier and more straightforward to think about.

Or 64bit fixed point as it has the same precision over the whole range.

( sorry I come back… but something interresting I forgot to point is that ALL Math class method (like trigo function) use double as input, this include : atan2,cos,exp,tan,toDegree,toRadian etc… )

Hehe. The point is if you don’t know why you’re using doubles instead of floats, you’re doing yourself a disservice. Unless you simply plan on using existing (hopefully correct) routines created by someone else.

For a chain of rotation compositions, use quaternions. Much more stable and when errors start to compound, the normalization is easier. (FWI: A non-unit quaternion acts as a rotation + a scale, where the scale factor is its magnitude squared).

(EDIT: Since it slowly creeps away from unity, you can do something like a single newton-ralphson step to push it back)

or you dont know why you are using float…

I use double because :

  • I like precision
  • It run most of the time as fast as float
  • I cant see any reason to use float when you can use double

basically 90% of time for my project I use int for integer computation & double for floating computation

Which is just limitation of Java API :slight_smile: For example C math library has float versions. Also HotSpot seems to optimize eg. (float)Math.sqrt(floatArg) to float sqrt instead of using double version (don’t remember where in HotSpot code it is, but this link should suffice as a proof). Dunno why they didn’t just add float versions and instead did these workarounds.

To be back ontopic, OP asked and I explain why I adviced to use double providing differents sample, feel free to explain why he should use float instead… Plz dont argue opengl. …

let do another test…


    	double resultDouble = 0.0;
    	float resultFloat = 0.0f;
    	int resultInt =0;
    	
    	long startTime=System.currentTimeMillis();
    		for(int n=1;n<100;n++)//nb: multiple call to get precise bench ...
    			resultDouble = testSumDouble();
    	long endTime=System.currentTimeMillis();
    	
    	long doubleTime=endTime-startTime;
    		
    	startTime=System.currentTimeMillis();	
    		for(int n=1;n<100;n++)//nb: multiple call to get precise bench ...
    			resultFloat = testSumFloat();
    	endTime=System.currentTimeMillis();
    	
    	long floatTime=endTime-startTime;
    	
    	startTime=System.currentTimeMillis();	
    		for(int n=1;n<100;n++)//nb: multiple call to get precise bench ...
    			resultInt +=testSumInt();
    	endTime=System.currentTimeMillis();
    	
    	long intTime=endTime-startTime;
    	
    	
    	System.out.println("Test Double Sum" + resultDouble + " computed in " + doubleTime + "ms => global error " + 100*Math.abs(1000000/resultDouble-1.0) + "%");
    	System.out.println("Test Float Sum= " + resultFloat + " computed in " + floatTime + "ms => global error " + 100*Math.abs(1000000/resultFloat-1.0) + "%");
    	System.out.println("Exact result = 1000000");
    	System.out.println("Test Int Sum= = " + resultInt + " need to print int result to avoid JIT optim and time "  + intTime + "ms for int test to show that it is not the loop that eat all the time...");
    	System.out.println ("");

output :

Test Double Sum999999.9998389754 computed in 1342ms => global error 1.6102452704558345E-8%
Test Float Sum= 1087937.0 computed in 1326ms => global error 8.082914352416992%
Exact result = 1000000
Test Int Sum= = 990000000 need to print int result to avoid JIT optim and time 889ms for int test to show that it is not the loop that eat all the time…

Conclusion :

about precision :
float error : about 8%
double error : less than 0.000…1%

about speed :
global difference : about 16ms => can be considered as not significant

so… yes, I still generaly prefer to use double, (need to mention that float implies a lot of cast too and the use of “f” suffix…), and really I definitly know why I prefer using double :wink:

I ve worked with float for long time in C/C++ (before going with java) and at that time I got good reason to do such but nowadays and with java double are better (wich is not yet the case between long and int)… my idea is that most people use float without really knowing why, and mostly because they have seen one doing such and than without looking further…

Everyone knows accumulation is one of worst cases so double for the temporary variable is the way to go in most cases unless the performance (eg. by using vectorized SSE2 code) is much more important. Otherwise floats are sufficient for most use cases. Takes half the memory, no need for conversions when passing into OpenGL and you can process 4x float at once with SSE2 instead of just 2xdouble (though not relevant for pure Java).

The argument about preferring it because of Java’s deficiencies in API and the way number literals works in Java (and which is just about being used to one particular style) is quite ridiculous. If you don’t like the casts you can fix the API by creating bunch of static methods that takes float as well.

Which you’re exactly doing, using double for everything without knowing why. In many cases it’s just wasteful. It’s like using long for everything instead of int. Sure matters little less on 64bit, but in some applications the twice size of pointers is quite significant overhead in memory.

And for example HotSpot has ability to use shifted 32bit pointers in 64bit mode so they can access 32GB of heap memory at maximum which is ok limit for most usages and takes less memory.

“ridiculous” ?! your incredible… I ve posted sample, given arguments… You tell about SSE and such but dont show anything, plz dont point to another or someone else article or bench… show your own one it will be easier to talk about. I never argue to always use double and I sometime use float for example to define object vertice in its local space ( only to save some memory ). really I can change my mind about double and float but it will requiere stronger arguments than “I eard. …” or “look at this article it say that…”

Heh, I’ve used the ‘ridiculous’ word for just one particular thing in that post and doesn’t apply to anything other.

My point is not much in convincing you to stop using doubles and replace them with floats, but saw this as a good opportunity to make discussion about this topic. In practice you can use doubles (on x86, but not eg. ARM) for most things without much problem, but what I don’t like is this attitude to use one tool (double) for everything without any thinking. There are also cases when even 32bit float is quite overhead, eg. in HDR images/colors where usage of 16bit float (half) is benefical.

About the samples, I did not feel I needed any for my points so far. Also beware that microbenchmarks can be misleading and the danger of them is well known, especially in JVM (where just reordering the tests can yield to very different values and you have to count with the JIT warmup). I base my observations based on whole apps and long-term experience with them. Some other statements are just matter of facts (eg. the 4xfloat vs 2xdouble in SSE2) or twice the memory amount / bandwidth needed.

ok, so lets talk on a peacer way

using float vs double wont make a weird algorithm becoming good ? 50% gain in bandwith and/or memory is nice but that’s not something that will make a real difference on most project, but inded all type of variable have its own area of usage, that’s why they exists.

[quote]Also beware that microbenchmarks can be misleading and the danger of them is well known, especially in JVM
[/quote]
yes I know… that’s also why that in the bench I ve posted I favored float by putting double computation first while jvm warmup may not be finished, exaclty to avoid this suspicion of unfair bench and to avoid such discussion … let me guess the next one : I ve used currentMillis wich is not enought accurate ? :stuck_out_tongue: (ok ok sorry kidding but that usually the two argument given by some unaware people…)

[quote]About the samples, I did not feel I needed any for my points so far. Also beware that microbenchmarks can be misleading and the danger of them is well known, especially in JVM (where just reordering the tests can yield to very different values and you have to count with the JIT warmup). I base my observations based on whole apps and long-term experience with them. Some other statements are just matter of facts (eg. the 4xfloat vs 2xdouble in SSE2) or twice the memory amount / bandwidth needed.
[/quote]
I eard that point, but it is also a matter of fact that byte take less memory than int and that you can do same computation than int using 4 bytes (but slower), but here the major difference is in the case of double vs float (in most desktop) you get more precision without speed cost, I just advice until you need a special requierement ( bandwith ? speed on some hardware probably ? ) use double instead of float and I still think it is a good advice.

I agree with the memory point and ARM (or other hardware) : but double is just the default for java that’s why until I get any good reason to use something else I start and continu a project with them, and if later I need more memory or target a different hardware I switch to something else, and I advice OP or anyone to do the same until they got good reason to do it another way, it seems more logical to me than starting with float.

once again just to be sure I well explained myself in pevious post : I never argue to “always” use doulble but rather than I often use them and use them as default (when not really knowing or when I dont care)

ps: arf… unfortunatly debat are always endless

Sorry to butt in but could we please end this here?
We have gotten way off topic and DzzD’s and jezek2’s arguments are the same: use double for precise and accurate calculations, floats for memory and time saving calculations.

Good? 8)

yes ! that’s a noble-minded advice (maybe moderator may split this one somewhere…)

hahaha, well I’m glad that’s settled!, I fear I may have skipped through some code that would have been needed to figure out why direction isn’t being reversed, so I’ll post ALL the relevant parts now instead of omitting what I thought would be minor details.

In my World class


if (e.getBounds().intersects(wall)) {
  ((Car)e).scaleVelocity(-1);
  ...

which is (not too sure if that is correct)


public void scaleVelocity(int scale) {
	velocity.scale(scale);
        position = Vector2D.add(position, velocity);
}

which leads to 2 methods inside my Vector2D class


public void scale(int scaleFactor) {
	x *= scaleFactor;
	y *= scaleFactor;
}

and


public static Vector2D add(Vector2D v1, Vector2D v2) {
	return new Vector2D(v1.x + v2.x, v1.y + v2.y);
}

I fear that my move method also plays a role into why the direction isn’t reversed so here is the essentials.


...
velocity = new Vector2D(magnitude * Math.cos(direction), magnitude * Math.sin(direction));
position = Vector2D.add(position, velocity);
...

I’m thinking that because move is called every time update is called the scaled velocity vector gets ditched for the new velocity vector and thus I never see the change in direction occur. That’s the best educated guess I can come up with, and I have no idea how to go about solving it.

A second pair of eyes would really do me some good! Thanks! :slight_smile:

I don’t think you should do Vector2D.add(position,velocity) in scaleVelocity(int). That’s an extra “move” when your character hits the wall.

Also maybe, just maybe you intersect the wall twice causing the velocity to be scaled by -1 twice so check your code.

Yes probably come from the twice reverse, you shoul keep trace of pos before moving and if colision happen restore old pos in addition to scale velocity

OldPos=Pos
Move()
if(colision)
{
Vitesse*=-1
Pos=oldpos
}

Yes, that’s basically it.

Currently what’s happening when the car collides is its velocity is reversed and added to its position, which has the effect of undoing the previous move(). (During move() the velocity is added to the position. On a collision, the velocity is subtracted from [its negative added to] the position. So the car is back where it started.) So the code is (inadvertently?) doing exactly what DzzD suggests – undoing the step that led to the collision.

But as you say, the reversed velocity vector subsequently gets overwritten by a vector derived from speed and direction. If you want the collision to permanently reverse the velocity (which may not be quite the effect you’re after, but let’s worry about that later) then you need to change the direction (as well as the velocity vector). That is, add Math.PI radians (= 180 degrees) to the car’s direction angle when you detect a collision.

Two other comments:

  • You might change the name of scaleVelocity() to something like scaleAndAddVelocity() to make it a bit less confusing.
  • In the scale() function, scaleFactor should probably be a double rather than an int (although I don’t want to trigger another argument about the pros and cons of different data types ::slight_smile: ).

Simon

I agree that this should be been split a long time ago. BUT, this is exactly not what anyone should take away from the floats vs. doubles debate. This is the common misconception of how floats and doubles work. What everyone should know is that a lack of knowledge of how floats work will eventually bite you in the butt. A malformed/numerical unsound solution is defective regardless of representation. Using doubles instead of floats simply moves the wall back a bit.