Операция с плавающей точкой Modulo
Я пытаюсь реализовать операцию уменьшения диапазона для тригонометрии. Но вместо этого я думаю, что было бы лучше просто выполнить операцию modulo pi/2 для входящих данных. Мне было интересно, какие алгоритмы существуют и эффективны для этой операции для 32-битной IEEE 754 с плавающей запятой?
Я должен реализовать это в сборке, поэтому fmod, деление, умножение и т.д. мне не доступны только с одной инструкцией. Мой процессор использует 16-битные слова, и я реализовал сложение, вычитание, умножение, деление, квадратный корень, косинус и синус 32-бит с плавающей запятой. Мне просто нужно уменьшить диапазон (модуль) для ввода значений в косинус и синус.
Ответы
Ответ 1
Я думаю, что стандартная библиотека fmod()
будет лучшим выбором в большинстве случаев. Здесь ссылка для обсуждения нескольких простых алгоритмов.
На моей машине fmod()
использует оптимизированный встроенный код сборки (/usr/include/bits/mathinline.h
):
#if defined __FAST_MATH__ && !__GNUC_PREREQ (3, 5)
__inline_mathcodeNP2 (fmod, __x, __y, \
register long double __value; \
__asm __volatile__ \
("1: fprem\n\t" \
"fnstsw %%ax\n\t" \
"sahf\n\t" \
"jp 1b" \
: "=t" (__value) : "0" (__x), "u" (__y) : "ax", "cc"); \
return __value)
#endif
Таким образом, на самом деле для вычисления используется специальная команда CPU (fprem).
Ответ 2
Может быть, мне не хватает смысла здесь, но
у вас есть что-то против простого использования fmod?
double theta = 10.4;
const double HALF_PI = 2 * atan(1);
double result = fmod(theta, HALF_PI);
Ответ 3
Алгоритм, который вы хотите, ограничить плавающую точку value
между 0
и некоторым модулем n
:
Double fmod(Double value, Double modulus)
{
return value - Trunc(value/modulus)*modulus;
}
например pi mod e
(3.14159265358979 mod 2.718281828459045)
3.14159265358979 / 2.718281828459045
= 1.1557273497909217179
Trunc(1.1557273497909217179)
= 1
1.1557273497909217179 - 1
= 0.1557273497909217179
0.1557273497909217179 * e
= 0.1557273497909217179 * 2.718281828459045
= 0.42331082513074800
pi mod e = 0.42331082513074800