|
|
Регистрация Восстановить пароль |
Повторная активизация e-mail |
Регистрация | Задать вопрос |
Заплачу за решение |
Новые сообщения |
Сообщения за день |
Расширенный поиск |
Правила |
Всё прочитано |
|
Опции темы | Поиск в этой теме |
07.02.2010, 01:31 | #1 |
php / delphi
Форумчанин
Регистрация: 10.06.2007
Сообщений: 175
|
Оптимизация sin() на BASM
Уважаемые, Кодеры! Помогите пожалуйста ускорить функцию вычисления sin(x) через полином в форме Горнера (Delphi).
История проблемы: Для вычисления sin(x) при x=[-Pi/2,Pi/2] вполне достаточно учесть 3 члена ряда. Сия замечательная функция реализуется вот так: Код:
Код:
Вроде решение очевидно -> использовать симметрию функции, но нельзя использовать условные конструкции (в перспективе алгоритм будет распараллеливаться -> ветвления губительны) Собственно задача: Существует отличная формула приведения, позволяющая свести вычисление синуса произвольного угла к [-Pi/2, Pi/2] : sin( n*Pi+y ) = (-1)^n * sin( y ) Нужно дополнить функцию Asin(x). Ломаю голову как эффективно выделить n и y и возвести (-1)^n и затратить при этом меньше тактов, чем для mysin_11(x). Вообще есть способ избежать операции деления? Зы: Везде двойная точность
G.Azamat { Web Development / Computer simulation }
Начинающий программист думает, что в килобайте 1000 байтов, а законченный уверен, что в километре 1024 метра. Последний раз редактировалось InternetStranger; 07.02.2010 в 01:44. |
08.02.2010, 04:27 | #2 | |
Участник клуба
Регистрация: 11.01.2010
Сообщений: 1,139
|
InternetStranger
не очень понял, но попробую помочь 1) как эффективно возвести (-1)^n и затратить при этом меньше тактов проверить последний бит у n если 0, то (-1)^n=1 если 1, то (-1)^n=-1 2) Вообще есть способ избежать операции деления? умножение занимает меньше времени, чем деление, поэтому, если делят на константу х, то предварительно находят обратную ей 1/х и заменяют деление на умножение 3) а зачем искать синус рядами используя команды fpu? если в fpu есть команды fsin и fsincos, а для вычисления arcsin(x) используют fpu-шную команду fpatan arcsin(x)=arctg(tg(x))=arctg(sin(x)/sqrt(1-sin(x)^2)) Цитата:
x=n*Pi + y y = x mod Pi (остаток от деления х на Pi) n = x div Pi (целочисленное деление х на Pi) последний бит(n) = n and 1 или последний бит(n) = n mod 2 Последний раз редактировалось Mikl___; 08.02.2010 в 11:48. |
|
08.02.2010, 16:25 | #3 |
php / delphi
Форумчанин
Регистрация: 10.06.2007
Сообщений: 175
|
Спасибо за советы ) Половину проблемы ты мне уже разрешил! ))
1) Проверяя последний бит у n, я так понимаю, мы проверяем на четность? ( ааа. сообразил -> это проверка кратности двум)) Даже если это так, интересно конечно, но мне нельзя использовать условные переходы -> иначе не смогу распараллеливать потом алгоритм. Хотя... С учетом твоего совета в голову вот что пришло: (-1)^n = 1 + (n and 1)*(-2) = 1 - (n and 1) shr 1 Всего одна вещественных операция + по мелочи (shr - выполняется вроде за один такт, and наверное тоже). Вот про это я и говорил, спасибо ))) 2) Действительно, вообще сглупил. Pi - это же константа. Пора завязывать ночами напролет кодить Но этот вопрос снимается уже - я просто нормировал (сделал замену переменной) все уравнение вместе с входящим в него синусом. Теперь осталось реализовать собственно операцию: n= trunc (x), y = frac(x) (Чтобы воспользоваться формулой приведения, предварительно нужно вычислить n и y ). Или я плохо знаю матчасть, но mod и div в качестве операндов принимают Целые числа , а не Double? Я как-то всю жизнь считал не применимыми к вещественной арифметике. 3) А производительность в тактах этой команды известна? С тем учетом, что считает она до 15го знака после запятой и на всей области -> мне столько не нужно )) Ряд до определенной длины сосчитать быстрее, чем вызвать эту команду (Ну как-то так я посчитал). Это если при вычислении ряда воспользуешься самыми базовыми операциями - * + - shl shr. Итак, с учетом вышесказанного, что же мне еще осталось сделать (Для наглядности полу-оптимизированный Delphi - эквивалент ): Код:
Т.е. теперь проблема формулируется так -> как числа двойной точности достать целую и дробные части? Так-то я пробовал fist, но резобрался в какую сторону она округляет.
G.Azamat { Web Development / Computer simulation }
Начинающий программист думает, что в килобайте 1000 байтов, а законченный уверен, что в километре 1024 метра. Последний раз редактировалось InternetStranger; 08.02.2010 в 17:11. |
09.02.2010, 04:11 | #4 | ||
Участник клуба
Регистрация: 11.01.2010
Сообщений: 1,139
|
InternetStranger
Если требуется скорость для вычисления sin, то для чего тогда использовать fpu? Для больших скоростей используют целочисленную арифметику, а при вычислении тригонометрических функций используют табличное преобразование -- величина программы я думаю тебя не интересует, а значения угла как правило с определенным шагом получают с какого-нибудь датчика, погрешность измерения это и определяет точность вычисления Цитата:
fld Angle; от -2 до 8 fldpi; загрузили pi= 3,141593265358979323… fdiv st(1),st(0) fld st(0); дублируем результат frndint; округляем до целого fist n; сохраняем целую часть fsub st(1),st(0); получаем остаток Но всеравно, я считаю, что встроенная fsin считает быстрее, чем вычислять синус рядами, и это необходимо тебе проверить Цитата:
Синтаксис команды: FRNDINT Семантика команды: Команда округления до целого Псевдокод команды: ST(0)<--RoundToIntegerValue(ST(0)) Эта команда округляет текущее содержимое вершины стека до целого числа. Биты RC (Rounding Control) в регистре управления (RCW) определяют способ округления результатов команд блока FPU до заданной точности RC |Способ округления 00b| к ближайшему числу near 01b| к -∞ down 10b| к +∞ up 11b| к нулю chop/zero Код:
rc=0 (режим округления к ближайшему числу); флаги особых ситуаций в регистре SWR сброшены; флаги запрета прерываний в регистре CWR по особым ситуациям установлены; TOP=7. Последний раз редактировалось Mikl___; 09.02.2010 в 05:19. |
||
11.02.2010, 00:55 | #5 |
php / delphi
Форумчанин
Регистрация: 10.06.2007
Сообщений: 175
|
Спасибо за подробное разъяснение этой инструкции.
Буду разбираться )) Осталось немного до полноценной победы над синусом (а борюсь я с ним уже больше месяца)). 1) Целочисленная математика для меня не вариант, я уже не раз пытался свести мое уравнение к целым числам. все безуспешно. 2) Таблицы - тоже пройденный этап. У меня ж задача научная - все подсчитано. Для моей задачи (вернее необходимой точности) потребуется таблица ~ 4 мегабайта . К тому же просто навскидку подумай, думаешь получится организовать быстрый доступ к значениям этой таблицы, когда у меня аргументы дробные. Это опять округления, отбрасывания вещественной части части и прочее.... По поводу таблиц ты конечно прав отчасти. Они используются: 2.1) там, где не требуется высокая точность. Например, при рисовании графики. 2.2) там, где требуется очень большая точность. тут таблицы - это отправные точки для итерационных методов ( вот эти алгоритмы кстати эффективнее полиномиального разложения для точности > 1e-10 ) Понимаю, выглядит на борьбу с тенью... Вообще вопрос не столько программерский - больше философский: "Чтобы решить проблему, нужно прежде осознать, что она существует". А вычисление синуса - это действительно проблема. Ведь большинство считает, что алгоритмы крупных компаний (aka AMD, Intel, nVidia...) наилучшие )) Ничего гениального там нет- пользуются они математикой, придуманной еще 17-19 веках. Ряд Тейлора/Маклорена вроде даже раньше )) Я даже на 99% знаю какая аппаратная реализация используется в сопроцессорах ( см. пункт 2.2 ). А также ее сильные и слабые стороны. И вот за этой инструкцией "fsin" кроется куча не нужных и кое-каких бесполезных действий. Это всмысле для точности 1e-5 (которая нужна мне).
G.Azamat { Web Development / Computer simulation }
Начинающий программист думает, что в килобайте 1000 байтов, а законченный уверен, что в километре 1024 метра. |
11.02.2010, 00:56 | #6 | ||
php / delphi
Форумчанин
Регистрация: 10.06.2007
Сообщений: 175
|
Ну довольно лирики...
Цитата:
Итак, стоит задача рассчитать синус с точностью до 1e-5 в пределах [0..Pi]: Код:
Цитата:
Прошу громко не пинать ( ассемблером владею всего пару дней, с даты первого поста этой темы ), а при необходимости указать где чего поменять для объективности результатов тестирования. Эти значения имеют смысл только при сравнении между собой. Но 27.85 - это, кстати, тоже многовато )) Существуют и другие способы подсчета суммы полинома. Но это уже совсем другая история... ЗЫ: в принципе необязательно было даже ухитряться и измерять. Достаточно просто заглянуть вот сюда: Intel®64 and IA-32 Architectures Optimization Reference Manual (ноябрь 2009), чтобы раз и навсегда отбило желание использовать fsin )) Наиболее интересны страницы 569 и 570.
G.Azamat { Web Development / Computer simulation }
Начинающий программист думает, что в килобайте 1000 байтов, а законченный уверен, что в километре 1024 метра. Последний раз редактировалось InternetStranger; 11.02.2010 в 01:31. |
||
Похожие темы | ||||
Тема | Автор | Раздел | Ответов | Последнее сообщение |
Получить значения функции sin(x) (Pascal) | Женек | Помощь студентам | 1 | 30.01.2010 00:23 |
Cos, Sin и непонятности с ними =\\ | Zeraim | Общие вопросы Delphi | 3 | 25.07.2009 01:38 |
Ряд Тейлора, sin, cos... | Kostia | Общие вопросы Delphi | 6 | 05.10.2008 10:13 |
Процедура, вычисляющая Y=a*cos(G) и X=a*sin(G) | Vishez | Помощь студентам | 4 | 25.04.2007 17:41 |