0

I wrote a program that simulates perfectly elastic collisions in 1D using an event-driven algorithm. The problem is something akin to Newton's cradle.

I was trying to fix something I perceive to be an issue, which is that when I give two spheres an equal initial velocity, the position and velocity arrays are updated twice due to simultaneous collisions (and thus I get a double output for the same instant).

To this effect, I created a variable that would check whether the next collision would happen within 0 seconds (i.e.: "now"). However, when I do that, the time until the collision changes completely for those simultaneous collisions.

There are 5 particles in total, and each one has a radius of 1, with a separation of 0.5 between them. Collisions are perfectly elastic, gravity is disregarded, and the algorithm stops when the final particle hits a wall placed arbitrarily in front of it.

Initial velocity for the first two particles is 1, so the first collision should occur after 0.5, and the second and third collisions should occur simultaneously after another 0.5.

Before adding the variable to check whether or not the time until collision is 0, the time until collision was outputted as 6.94906e-310 (this was verified by outputting the return value of the function that calculates the time until collision).

With the new variable that was going to be used to check if the previous value was zero, the time until collision during a simultaneous collision is now outputted as -1 in both the new variable and the return value of the aforementioned function.

I'm guessing this has something to do with the fact that it's an extremely small double value, but I don't quite understand the problem. How could creating one variable affect the value of another (albeit somewhat related) variable to this extent?

The code below is just to help visualize the problem. It is not a MWE. I'd have to post almost my entire code here to produce a MWE. Because this is for a class, I could get plagiarized or be accused of plagiarism myself, so I don't feel comfortable posting it.

Again, not a MWE, just to better explain what I'm doing.

//x and v are arrays with the positions and
//velocities, respectively, of each particle
//hasReachedWall(x) checks if the last particle has hit the wall
while (!hasReachedWall(x)) {
    //The return value of updatePos(x, v) is a double with the time until the next collision
    //aux, is the cause of the problem. Its existence somehow changes
    //the return value into -1 when it should be near-zero. Without this variable,
    //the return value is as expected (near-zero)
    double aux = updatePos(x, v);
    cout << aux << endl;
    //t is also a double
    t += aux;
}

EDIT: I am aware of how doubles are stored internally and that operations performed on them have errors. My problem is that the mere creation of an intermediary variable completely changes the result of an operation.

I'm creating a double to store the return value of a function (another double - not long double, just double), and the return value of the function changes radically. I don't understand why.

Orion
  • 87
  • 8
  • So previously you just had `t += updatePos(x, v);`? And the return type of `updatePos` is `double`? What is the type of `t`? – Harry Dec 01 '19 at 12:57
  • Indeed. ```t``` is also a double. Everything works perfectly, except when I create that variable (aux), even though it just serves as an intermediary. I'd never seen such a thing before. – Orion Dec 01 '19 at 12:58
  • Does this answer your question? [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) FP math is inexact I think this is what you are experiencing. It's a well know issue in simulations that when using FP math the simulation can run away (gain energy) or do other unexpecting things. – Richard Critten Dec 01 '19 at 12:59
  • @RichardCritten It doesn't. I'm well aware of those inaccuracies. I'm just creating an intermediary to temporarily store a double, which should not change the result of a different calculation. Please read the question. – Orion Dec 01 '19 at 13:01
  • 1
    Creating a new variable can force the store of 80-bit (CPU/FPU doubles) into 64-bit IEEE doubles this changes the value of the double. (assuming modern Intel CPU and compilation options). – Richard Critten Dec 01 '19 at 13:03
  • Wouldn't I need to declare it as a long double for the first variable to be stored as an 80-bit double? – Orion Dec 01 '19 at 13:08
  • Depends on the exact compilation options but by default most of the mainstream compilers default to 80-bit CPU/FPU doubles and 64-bit doubles when stored. Check your compiler's FP maths options. So a complex expression with temporaries can be all 80-bit. But if it is broken up and intermediate result stored they get stored as 64-bit. This can/will change the final result. – Richard Critten Dec 01 '19 at 13:20
  • I'll try to find out how to do that. However, I should point out that the value is stored in a variable contained within the function itself before being returned (because it needs to be compared with a few other values due to the physics of the system, it's a long and boring story). Wouldn't that have caused the same problem before? – Orion Dec 01 '19 at 13:23

0 Answers0