So I'm having what seems to me to be a very bizarre problem. I've got a crude system for applying forces to objects on 2D planes, and one of the simplest calculations seems to be causing one of my variables to overflow. I have the following line:
int ySign = m_Momentum.y / abs(m_Momentum.y);
Where Momentum has two data members, x
y
(m_Momentum is an SFML sf::Vector2 of floats). Now, normally the formula should always return either 1 or -1, depending on the sign of Momentum.y (unless I'm grossly mistaken).
However, it occasionally returns insanely high numbers such as -2147483648. In that particular case, the value of m_Momentum.y was 0.712165 (both values were obtained by sending to std::cout); I tried again, m_Momentum.y was -0.578988 and ySign was still -2147483648. There is a corresponding xSign that also flips out sometimes, often with the same final value. I can't confirm 100% that this is always the result, but at the moment that seems to be the case.
I'm sort of stumped as to why this is happening, and when it does, it basically invalidates my program (it instantly sends objects millions of pixels in the wrong direction). It seems logically impossible that the line above is returning such strange results.
Below is the function I am working on. Probably the wrong way to do it, but I didn't expect it to go so horribly wrong. The printout it produces reveals that all numbers look normal until the signs are printed out; one of them is invariably massive, and afterwards you see numbers like -2.727e+008 (which, as far as I'm aware, is scientific notation - i.e. -2.727 * 10 ^ 8).
///MODIFY MOMENTUM
//Reset, if necessary
if (Reset == true)
{
m_Momentum.x = 0;
m_Momentum.y = 0;
}
sf::Vector2<float> OldMoment = m_Momentum;
//Apply the force to the new momentum.
m_Momentum.x += Force.x;
m_Momentum.y += Force.y;
sf::Vector2<float> NewMoment = m_Momentum;
//Calculate total momentum.
float sqMomentum = m_Momentum.x * m_Momentum.x + m_Momentum.y * m_Momentum.y;
float tMomentum = sqrt(sqMomentum);
//Preserve signs for later use.
int xSign = m_Momentum.x / abs(m_Momentum.x);
int ySign = m_Momentum.y / abs(m_Momentum.y);
//Determine more or less the ratio of importance between x and y components
float xProp;
float yProp;
if (abs(tMomentum) > m_MaxVelocity)
{
//Get square of maximum velocity
int sqMax = m_MaxVelocity * m_MaxVelocity;
//Get proportion of contribution of each direction to velocity
xProp = (m_Momentum.x * m_Momentum.x) / sqMomentum;
yProp = (m_Momentum.y * m_Momentum.y) / sqMomentum;
//Reset such that the total does not exceed maximum velocity.
m_Momentum.x = sqrt(sqMax * xProp) * xSign;
m_Momentum.y = sqrt(sqMax * yProp) * ySign;
}
///SANITY CHECK
//Preserve old tMomentum
float tOld = tMomentum;
//Calculate current tMomentum
sqMomentum = m_Momentum.x * m_Momentum.x + m_Momentum.y * m_Momentum.y;
tMomentum = sqrt(sqMomentum);
//If it's still too high, print a report.
if (tMomentum > m_MaxVelocity)
{
std::cout << "\n\nSANITY CHECK FAILED\n";
std::cout << "-\n";
std::cout << "Old Components: " << OldMoment.x << ", " << OldMoment.y << "\n";
std::cout << "Force Components: " << Force.x << ", " << Force.y << "\n";
std::cout << "-\n";
std::cout << "New Components: " << NewMoment.x << ", " << NewMoment.y << "\n";
std::cout << "Which lead to...\n";
std::cout << "tMomentum: " << tOld << "\n";
std::cout << "-\n";
std::cout << "Found these proportions: " << xProp << ", " << yProp << "\n";
std::cout << "Using these signs: " << xSign << ", " << ySign << "\n";
std::cout << "New Components: " << m_Momentum.x << ", " << m_Momentum.y << "\n";
std::cout << "-\n";
std::cout << "Current Pos: " << m_RealPosition.x << ", " << m_RealPosition.y << "\n";
std::cout << "New Pos: " << m_RealPosition.x + m_Momentum.x << ", " << m_RealPosition.y + m_Momentum.y << "\n";
std::cout << "\n\n";
}
///APPLY FORCE
//To the object's position.
m_RealPosition.x += m_Momentum.x;
m_RealPosition.y += m_Momentum.y;
//To the sprite's position.
m_Sprite.Move(m_Momentum.x, m_Momentum.y);
Can somebody explain what's going on here?
EDIT: RedX helpfully directed me to the following post: Is there a standard sign function (signum, sgn) in C/C++? Which led me to write the following lines of code:
//Preserve signs for later use.
//int xSign = m_Momentum.x / abs(m_Momentum.x);
//int ySign = m_Momentum.y / abs(m_Momentum.y);
int xSign = (m_Momentum.x > 0) - (m_Momentum.x < 0);
int ySign = (m_Momentum.y > 0) - (m_Momentum.y < 0);
Thanks to the above, I no longer have the strange problem. For an explanation/alternative solution, see Didier's post below.