Closed Schroedingers-Hat closed 12 years ago
I put it there because, at the time, translating to a frame identical to the current frame caused problems -- everything turned to NaN. I'm not sure if this is still the case or if there's a better way to fix it.
Ah, there's probably a divide by zero or an imaginary somewhere. Should be able to fix it by refactoring an equation somewhere. Will keep this open as a bug until we need this feature.
Poked through things a bit, this looks like it's probably the same issue as 59 Things that will help: 64 bit precision, will give you another 9 orders of magnitude before this comes into effect (if it is the problem). Re-factoring some of the maths: Many of the formulae can be rearranged to reduce the effect of (or eliminate) subtracting numbers that are close/dividing by things close to zero, etc
Found it, figures it'd be in the least pleasant piece of maths.
function cBoostMat(boostV,c) { var boostMagSq=boostV[1]_boostV[1]+boostV[2]_boostV[2]; var gamma=vToGamma(boostV); return (mat4.create([gamma, -boostV[1]_gamma, -boostV[2]_gamma, 0, -boostV[1]_gamma, 1+(gamma-1)_boostV[1]_boostV[1]/boostMagSq, (gamma-1)_boostV[1]_boostV[2]/boostMagSq, 0, -boostV[2]_gamma, (gamma-1)_boostV[1]_boostV[2]/boostMagSq, 1+(gamma-1)_boostV[2]_boostV[2]/boostMagSq, 0, 0, 0, 0, 1 ])); };
This goes a bit whack as boostmagsq and gamma -1 approach zero. Expanding gamma out and re-factoring might help. @capnrefsmmat I don't suppose you feel like some algebra? ^_^
A helpful reference:
http://download.oracle.com/docs/cd/E19957-01/806-3568/ncg_goldberg.html#700
As gamma approaches 1, we get catastrophic cancellation. Right? We can try to refactor the equations as explained in the article.
(Now, is it a different problem that causes gamma < 1 in issue #59?)
Ah, catastrophic cancellation, that's a good name for it. I was struggling to describe. :D There is another almost identical issue that pops up sometimes (59 is a combination of both issues) where 1-blah approaches zero and we take a square root, resulting in NaNs when round-off makes it negative. Refactoring equations doesn't work quite as well here as they're often too simple.
So do you think 64-bit values are the best option, or should we give refactoring a shot?
Well, 64 bit may be a good idea regardless as we get ~5000 acceleration/rotations before round-off becomes detectable. Re-factoring that matrix will help with this. There are also going to be some values which we have to put manual checks on regardless (64 bit won't help as some things are dividing/multiplying by exactly zero).
Refactoring equations doesn't work quite as well here as they're often too simple.
Re-factoring that matrix will help with this.
So wait... should I try to refactor it, following the catastrophic cancellation instructions, or not?
Positions are currently represented using glMatrix's quat4, which defaults to Float32Array. Just set glMatrixArrayType = Float64Array
somewhere before any quat4s are defined and you can test the impact of 64-bit floats. I'm curious to see if it has any performance impact.
I'll probably get around to doing it eventually, but it'd be great if you feel like having a go. There's a copy of the matrix here: http://en.wikipedia.org/wiki/Lorentz_transformation#Matrix_form you can leave Bz (boostV[3]) as 0, or include it in the calculations, it won't make any difference right now (but may be useful later).
when I said 'Refactoring equations doesn't work quite as well here as they're often too simple.' I was talking about a couple of other bits, where I've already done it the lazy way rather than refactoring. Such as this (the Math.max.... ): this.radialVPast = (quat4.spaceDot(this.XView, this.V) / Math.max(Math.sqrt(Math.abs( quat4.spaceDot(this.XView, this.XView) )),1e-10) / this.V[0]);
I'd like to keep that sort of thing to places where errors are not cumulative though.
I'll have a go at it later tonight.
Tried the 64 bit thing out. Seemed to slow things down by 10-20% for our calculations. Doesn't seem to effect drawing time, so the impact overall is negligable (~5%).
In the quick test (w/ or w/o 64 bit) drawing seemed to be a lot slower than it was previously (~ an order of magnitude). Could just be because I had lots of large things all on top of one another (along with text visible), as I couldn't be bothered re-creating the random-generation code.
@Schroedingers-Hat: I'm working on fixing cBoostMat's units first. The matrix form of the Lorentz transformation uses beta_x, beta_y, and so on, which I presume would be V[1]/c, V[2]/c, and so on. However, the velocity matrix is run through quat4.scale before being passed to cBoostMat and each element is divided by V[0] (gamma, I presume), and if I divide each velocity term by c I get incorrect frame changes. Could you explain what the quat4.scale does and how this should work? Am I misreading the meaning of beta_x?
(Also, I assume that boostMagSq has to be divided by c^2 as well.)
Dividing everything by V0 would make it dimension-less. Looks like I did it so that the V I passed to cBoostMat would be three-velocity not four-velocity. Suggestions: Either rename it to make this fact more apparent (traditional symbol for V/c (this value) is Beta, so maybe B?) Write a new function with a slightly different name, and I'll go through and replace it on a step by step basis.
Other info, quat4.scale(a,b,c) works as follows the quat4 a is scaled linearly by the scalar b and stored in c if it is present. If not, it is edited in place.
glMatrix non obsfucated source is here http://code.google.com/p/glmatrix/source/browse/glMatrix.js
f8eab49a86 significantly changes the behavior of cBoostMat. We should check whether this issue still exists, and if so, start nailing it down to specific variables and expressions to be adjusted.
The original problem (translating to a frame identical to the current frame caused problems) no longer causes issues, so I'm going to call this closed.
this // If the new frame is basically the same as the old frame, don't bother. if (Math.sqrt(quat4.spaceDot(XShift, XShift)) < 0.0001 && Math.sqrt(quat4.spaceDot(obj.COM.V, obj.COM.V)) < 0.0001) { return;
is going to cause some confusion if we go to make demos at ordinary (non-relativistic) speeds/scales @capnrefsmmat i take it you put it there to stop people repeatedly clicking on some object they're at/right beside or similar?