Разные результаты для одних и тех же вычислений с плавающей запятой

В задании по трассировке лучей, которое я выполняю, я должен вычислить X-смещение луча, стреляющего из камеры; расчет смещения выглядит так

FovY дается как вход; Я не забыл преобразовать его в радианы в тот момент, когда я прочитал переменную.

OffsetX = tan (FovX / 2) * ((col - (width / 2)) / (width / 2))

FovX = tan(FovY / 2) * aspect = tan(FovY / 2) * (width / height)

Подставим в исходное уравнение и напишем код:

float OffsetX = tan(FovY / 2.0f) * (width / height) * ((col - (width / 2.0f)) / (width / 2.0f));

дал мне неправильное растянутое изображение, и мне потребовались часы, чтобы исправить его, после того как я обнаружил, что то же самое уравнение работает после его упрощения.

Окончательное переставленное уравнение было:

float OffsetX = tan(FovY / 2.0f) * (2.0f / height) * (col - (width / 2.0f));

Я пробовал отладку, и действительно, результаты для обоих уравнений были разными.

Будет ли какая-то ошибка округления? Может кто-нибудь объяснить мне эту странность?

#include <cmath>
#include <iostream>
#include <cstdint>

using namespace std;

int main()
{
    const float PI = 3.1415f;
    const uint32_t width = 160, height = 120;
    const auto fovy = (30.0f * (PI / 180.0f));
    size_t j = 0;
    auto alpha = (tan(fovy / 2.0f) * (width / height)) * (((j + 0.5f) - (width / 2.0f)) / (width / 2.0f));
    cout << alpha << endl;
    alpha = tan(fovy / 2.0f) * (2.0f / height) * ((j + 0.5f) - (width / 2.0f));
    cout << alpha << endl;
}

person legends2k    schedule 12.12.2012    source источник
comment
Не могли бы вы предоставить полный работающий пример, показывающий оба способа вычисления результата и показывающие некоторые входные данные, в которых эти два метода расходятся. Это устранит много двусмысленности в вашем вопросе.   -  person NPE    schedule 13.12.2012
comment
Если вы не можете показать два разных фрагмента кода, которые воспроизводят поведение, касающееся вас, вам будет трудно помочь.   -  person David Heffernan    schedule 13.12.2012
comment
Мне потребовалось пару минут, чтобы обновить его кодом, когда я обнаружил, что это необходимо; внутри этого кто-то проголосовал за этот вопрос :(   -  person legends2k    schedule 13.12.2012


Ответы (1)


Дайте угадаю: ширина и высота — целые числа.

Когда вы делаете:

(width / height)

вы получаете целочисленное деление, которое отбрасывает дробную часть результата. Если вы вместо этого сделаете:

((double)width / height)

тогда два результата будут почти идентичными.


кроме того, вы можете еще больше упростить выражение:

tan(FovY / 2.0f) * (2.0f*col - width) / height
person Stephen Canon    schedule 12.12.2012
comment
Это распространенная ошибка, а психическая отладка — моя специальность. знак равно - person Stephen Canon; 13.12.2012
comment
@StephenCanon: Что ж, так мне будет проще отправлять вам отчеты об ошибках. - person Eric Postpischil; 13.12.2012
comment
Сколько инженеров Apple нужно для выполнения такого задания? ;) - person Yann Droneaud; 19.12.2012