Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Как реализованы функции cos(x) exp(x) в math.h ?
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Костян
Собственно интересует метод реализации функций cos(x) и exp(x) . Как они вычисляются ? Таблично , посредством ряда фурье или ... ?
scifi
Можно подглядеть у newlib.
Вот синус-косинус:
sf_sine.c
Вот экспонента:
sf_exp.c
kosyak©
Скорее всего ряд Тейлора.
_Pasha
Цитата(kosyak© @ Jan 28 2010, 11:03) *
Скорее всего ряд Тейлора.

sf_sine.c
Код
   /* Calculate the Taylor series. */

smile.gif
Serj78
Библиотека math.h, входящая в состав кейла, по- видимому также использует ряд Тейлора. Причем количество членов воидимо какое-то ужасное, судя по времени выполнения. На AVR из его библиотеки float sin(float x) выполнялся впятеро быстрее, там было 5 членов ряда. smile.gif

Буду переписывать библиотеку- по времени выполнения математика меня не устраивает - медленнее чем на 8-ми битнике (AVR) работает при вчетверо большей тактовой.
А уж знаменито разрекламированная функция (hypot) вычисляющая длину двумерного вектора ( например, модуль комплексного числа ), это вообще песня. 0.76 мс!!! на 72-х мегагерцах...
blackfin
CORDIC
_Pasha
Цитата(blackfin @ Jan 28 2010, 21:54) *

Newlib весь безнадежно тормозной. И далеко не "new" smile.gif
artur_off
Цитата(Serj78 @ Jan 28 2010, 20:48) *
Библиотека math.h, входящая в состав кейла, по- видимому также использует ряд Тейлора. Причем количество членов воидимо какое-то ужасное, судя по времени выполнения. На AVR из его библиотеки float sin(float x) выполнялся впятеро быстрее, там было 5 членов ряда. smile.gif

Буду переписывать библиотеку- по времени выполнения математика меня не устраивает - медленнее чем на 8-ми битнике (AVR) работает при вчетверо большей тактовой.
А уж знаменито разрекламированная функция (hypot) вычисляющая длину двумерного вектора ( например, модуль комплексного числа ), это вообще песня. 0.76 мс!!! на 72-х мегагерцах...

Тоже столкнулся с проблемой очень медленной работы функций.
Код
tab_sin_U[i]=round((sin(temp)*amount)+(1/6)*(sin(3*temp)*amount));

Расчет массива из 1024-х значений по этой формуле, в STR912 занимал примерно пол секунды. И это при частоте ядра 96МГц.
scifi
Цитата(artur_off @ Jan 29 2010, 22:48) *
Тоже столкнулся с проблемой очень медленной работы функций.
Код
tab_sin_U[i]=round((sin(temp)*amount)+(1/6)*(sin(3*temp)*amount));

Расчет массива из 1024-х значений по этой формуле, в STR912 занимал примерно пол секунды. И это при частоте ядра 96МГц.

Формула как-то странно выглядит. Например, (1/6) - это 0. Возможно, что с типами других операндов напутано. Если можно не использовать double, то нужно внимательно проследить, чтобы везде был float. К тому же amount можно вынести за скобки и сэкономить одно умножение. Что делает round() и как - непонятно. Вывод: рано спешить с выводами про "быстро-медленно", сначала надо код подправить.
И вообще, что такое "очень медленная работа функций, и это с частотой ядра 96 МГц"? Эта фраза не имеет смысла, пока не сказано, сколько микросекунд - медленно, а сколько - быстро.
Drozd2
Если есть желание реализовать свой алгоритм, тогда исключительно CORDIC. Такой ответ уже был. Алгоритм очень хорошо срабатывает на ПЛИС. Весь просчет за один такт. Нужно только не забывать, что для точности, например, 32 бит нужно закладывать в расчет не меньше 33 бит. Еще лучше держат бит 5 в запасе. Очень удобный алгоритм, если нужно сразу получить и синис, и косинус числа. Прирост в скорости вычисления колоссальный. Даже на микроконтроллере без сопроцессора. Да и вообще, для любителей численных методов интересная тема.
Serj78
Цитата(Drozd2 @ Jan 31 2010, 02:23) *
Если есть желание реализовать свой алгоритм, тогда исключительно CORDIC. Такой ответ уже был. Алгоритм очень хорошо срабатывает на ПЛИС. Весь просчет за один такт. Нужно только не забывать, что для точности, например, 32 бит нужно закладывать в расчет не меньше 33 бит. Еще лучше держат бит 5 в запасе. Очень удобный алгоритм, если нужно сразу получить и синис, и косинус числа. Прирост в скорости вычисления колоссальный. Даже на микроконтроллере без сопроцессора. Да и вообще, для любителей численных методов интересная тема.


Готовых функций CORDIC не нашел, только алгоритм. Пока остановился на том, что и просто тупое копирование AVR-овской библиотеки от CVAvr (она, слава богу, открытая и на С писанная) дает примерно десятикратный прирост времени выполнения.

Возможно, в родной кейловской библиотеке больше точность, буду проверять. У меня дискретность значений примерно 50 микрорадиан.

Использовал функции в float синуса, косинуса и арктангенса ( на самом деле там один синус, остальные- через тригонометрические преобразования)
scifi
Цитата(Serj78 @ Jan 31 2010, 13:35) *
Возможно, в родной кейловской библиотеке больше точность, буду проверять. У меня дискретность значений примерно 50 микрорадиан.

Если такой маленький прирост, то наверняка можно оптимизировать при помощи локальной линеаризации.

Цитата(Serj78 @ Jan 31 2010, 13:35) *
Использовал функции в float синуса, косинуса и арктангенса ( на самом деле там один синус, остальные- через тригонометрические преобразования)

Если честно, не понимаю, как арктангенс можно получить из синуса тригонометрическими преобразованиями. Скорее всего никак нельзя. Ну да ладно, это к делу не относится...
artur_off
Цитата(scifi @ Jan 30 2010, 22:02) *
Формула как-то странно выглядит. Например, (1/6) - это 0. Возможно, что с типами других операндов напутано. Если можно не использовать double, то нужно внимательно проследить, чтобы везде был float. К тому же amount можно вынести за скобки и сэкономить одно умножение. Что делает round() и как - непонятно. Вывод: рано спешить с выводами про "быстро-медленно", сначала надо код подправить.
И вообще, что такое "очень медленная работа функций, и это с частотой ядра 96 МГц"? Эта фраза не имеет смысла, пока не сказано, сколько микросекунд - медленно, а сколько - быстро.


Это кусок кода с матлаба, так как сишный удалил. а на С естественно было приведение к float. хотя здесь протупил, вместо 1/6 можно было написать 0.167.
round() - математическое округление.
по поводу amount согласен, но это не так уж и сильно влияет на производительность.
По поводу времени выполнения было сказано, что занимает примерно пол секунды (0.5 с).
scifi
Цитата(artur_off @ Jan 31 2010, 15:29) *
Это кусок кода с матлаба, так как сишный удалил. а на С естественно было приведение к float. хотя здесь протупил, вместо 1/6 можно было написать 0.167.
round() - математическое округление.

Если везде float, то нужно использовать sinf() вместо sin(), roundf() вместо round(). 0.167 лучше писать как 0.167f, а если округление до трёх цифр не подходит, то 1.0f/6. Не сочтите за занудство, это на всякий случай. Скорее всего, у Вас так и написано.
Меня удивил round(), потому что в стандартной библиотеке Си его сразу не нашёл. Видимо, было добавлено в C99...
artur_off
Цитата(scifi @ Jan 31 2010, 15:45) *
Если везде float, то нужно использовать sinf() вместо sin(), roundf() вместо round(). 0.167 лучше писать как 0.167f, а если округление до трёх цифр не подходит, то 1.0f/6. Не сочтите за занудство, это на всякий случай. Скорее всего, у Вас так и написано.
Меня удивил round(), потому что в стандартной библиотеке Си его сразу не нашёл. Видимо, было добавлено в C99...


Благодарю за советы))).


А round() действительно добавлен в С99 и поэтому перед #include <math.h> надо объявить #define __USE_C99_MATH.
_Pasha
Цитата(scifi @ Jan 31 2010, 15:40) *
Если честно, не понимаю, как арктангенс можно получить из синуса тригонометрическими преобразованиями.

тута расписано все
Вообще прикольно! Я тоже вначале думал, что решается что-то типа методом ньютона...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.