Разделение поплавка на себя дает очень большие целые числа - PullRequest
3 голосов
/ 01 февраля 2012

Итак, у меня возникла, как мне кажется, очень странная проблема. У меня есть грубая система для приложения усилий к объектам на 2D-плоскостях, и один из самых простых расчетов, кажется, вызывает переполнение одной из моих переменных. У меня есть следующая строка:

int ySign = m_Momentum.y / abs(m_Momentum.y);

Если у Momentum есть два элемента данных, x y (m_Momentum - это SFML sf :: Vector2 с плавающей точкой). Теперь обычно формула всегда должна возвращать либо 1, либо -1, в зависимости от знака Momentum.y (если я не ошибаюсь).

Однако иногда он возвращает безумно большие числа, такие как -2147483648. В этом конкретном случае значение m_Momentum.y было 0,712165 (оба значения были получены путем отправки в std :: cout); Я попытался снова, m_Momentum.y был -0,578988, а ySign был -2147483648. Существует соответствующий xSign, который также иногда всплывает, часто с тем же конечным значением. Я не могу на 100% подтвердить, что это всегда результат, но в данный момент, похоже, это так.

Я в некотором роде озадачен тем, почему это происходит, и когда это происходит, это в основном делает недействительной мою программу (она мгновенно отправляет объекты миллионами пикселей в неправильном направлении). Кажется логически невозможным, что строка выше возвращает такие странные результаты.

Ниже приведена функция, над которой я работаю. Вероятно, неправильный способ сделать это, но я не ожидал, что это пойдет так ужасно неправильно. Распечатка, которую он производит, показывает, что все числа выглядят нормальными, пока знаки не распечатаны; один из них неизменно массивный, и после этого вы видите числа типа -2,727e + 008 (что, насколько я знаю, является научным обозначением, т. е. -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);

Может кто-нибудь объяснить, что здесь происходит?

РЕДАКТИРОВАТЬ: RedX услужливо направил меня к следующему сообщению: Есть ли стандартная функция знака (signum, sgn) в C / C ++? Что побудило меня написать следующие строки кода:

//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);

Благодаря вышесказанному у меня больше нет странной проблемы. Для объяснения / альтернативного решения см. Пост Дидье ниже.

Ответы [ 2 ]

8 голосов
/ 01 февраля 2012

Вы должны использовать fabs() вместо abs(), чтобы получить абсолютное значение числа с плавающей запятой. Если вы используете целочисленную абсолютную функцию, то результатом будет целое число ...

Например, -0.5 / abs(-0.5) обрабатывается как -0.5 / 0, что приводит к отрицательной бесконечности (как значение с плавающей запятой), которая преобразуется в минимальное значение типа int 0x80000000 = -2147483648

0 голосов
/ 03 февраля 2012

Принятие абсолютных значений и деление звуков, как ужасная трата циклов для меня. Что не так с

x > 0 ? 1 : -1

который вы всегда можете вставить в функцию

template <class T>
inline int sgn(const T &x) { return x > 0 ? : 1; }
...