Почему acos () приводит к «nan (ind)» при использовании результата скалярного произведения? - PullRequest
0 голосов
/ 02 сентября 2018

Я очень запутался с проблемой. Код, который я запускаю:

double dotProduct = dot(A, B);
std::cout << dotProduct << std::endl;
theta = acos(dotProduct);
std::cout << theta << std::endl;

Выход которого

-1
ANGLE: -nan(ind)

Тем не менее, следующие работы:

double dotProduct = dot(A, B);
std::cout << dotProduct << std::endl;
dotProduct = -1;
theta = acos(dotProduct);

Предоставление вывода:

-1
ANGLE: 3.14159

Кроме того, если я приведу dotProduct к float, acos () правильно выведет угол:

double dotProduct = dot(A, B);
std::cout << dotProduct << std::endl;
theta = acos((float) dotProduct);

Также в результате получается

-1
ANGLE: 3.14159

Для функции dot () я использую библиотеку Armadillo. Что я не понимаю, так это почему acos () должен работать, когда я устанавливаю dotProduct = -1, но не работает, когда он выводится функцией dot (). Что я делаю не так?

1 Ответ

0 голосов
/ 02 сентября 2018

Полагаю, что A и B являются нормализованными векторами, и поэтому вы ожидаете, что dot(A, B) будет между -1 и 1. С математикой с плавающей точкой это не обязательно верно. |dot(A, B)| может быть немного больше, чем 1. Бьюсь об заклад, если вы напечатаете его с большей точностью, вы увидите, что ваше значение немного меньше, чем -1.

Итак, вам нужно зажать dot(A, B) между -1 и 1. Или, что еще лучше, вызывайте acos() только, если ввод находится между -1 и 1:

double safe_acos(double value) {
    if (value<=-1.0) {
        return <pi>;
    } else if (value>=1.0) {
        return 0;
    } else {
        return acos(value);
    }
}

Это может быть немного быстрее, так как вы избегаете вызова acos() для значений вне пределов.

Примечание. Если вы занимаетесь трехмерной математикой, существует большая вероятность того, что вы вообще можете не звонить acos(). Используя тригонометрические тождества, обычно мы можем заменить это чем-то более быстрым и более точным решением.

...