Операция По Модулю С Плавающей Запятой
Я пытаюсь реализовать операцию сокращения диапазона для тригонометрии. Но вместо этого я думаю, что было бы лучше просто выполнить операцию по модулю pi/2 для входящих данных. Мне было интересно, какие алгоритмы существуют и эффективны для этой операции для 32-разрядного IEEE 754 с плавающей запятой?
Я должен реализовать это в сборке, поэтому fmod, деление, умножение и т. д. не доступны мне только с одной инструкцией. Мой процессор использует 16-битные слова, а я реализовал 32-битные сложение с плавающей запятой, вычитание, умножение, деление, квадратный корень, Косинус и синус. Мне просто нужно уменьшить диапазон (модуль) для ввода значений в Косинус и синус.
3 ответа:
Я думаю, что стандартная библиотека
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) для вычисления.
Может быть, я упускаю суть, но вы ничего не имеете против простого использования fmod?
double theta = 10.4; const double HALF_PI = 2 * atan(1); double result = fmod(theta, HALF_PI);
Алгоритм, который вы хотите, чтобы ограничить плавающую точку
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