На сайте habr.com/ru уже были похожие публикации осенью 2021 года:
Как посчитать синус быстрее всех
Не на Habr Как сделать быструю функцию для вычисления синуса? топик начат в 2003 году последний отклик в 2020 году.
Целью данной публикации попытка предложить способ расчета синуса и косинуса достаточно быстро для тех платформ, где отсутствуют эти функции (микроконтроллеры) или там где скорость расчета важнее точности.
Мне кажется, что выпуклые функции синус и косинус можно аппроксимировать не только рядом Тейлора ( многочленом вида a*x + b*x^3 +c*x^5 ... ) , а обычной параболой поведенной через точки 1,2,3 как на рисунке.
Точки 1 и 2 базовые, размещаются с определенным задаваемым шагом. В скрипте Scilab это переменная step. Координаты точки 3 будем вычислять таким образом, чтобы в ней было максимальное отклонение синуса ( или косинуса ) от отрезка 1-2.
Ниже приведены скрипты на Scilab для расчета коэффициентов полинома второй степени на интервале [ 0 ... pi /2] и графики отклонений для от функций синуса и косинуса .
Расчет коэффициентов для синуса на Scilab
/// синус
function [a,b,c]= koef_parabola(x1,y1,x2,y2,x3,y3)
/// расчет коэффициентов параболы по 3 точкам
a1= y3 - ( x3*(y2-y1)+ x2*y1 -x1*y2 )/( x2-x1)
a2= x3*( x3-x1-x2 ) + x1*x2
a= a1 /a2
b =( y2-y1)/( x2-x1) - a*( x1+x2)
c=( x2*y1 - x1*y2) / (x2-x1) + a * x1*x2
endfunction
kol_int =12 /// количество интервалов на отрезке 0 ... %pi/ 2
kol_funct =kol_int+1
step =%pi/ ( 2*kol_int) /// шаг
point0_x =0:step:%pi/ 2
point0_sin = cos(point0_x)
aa_sin =1:1:(kol_int)
bb_sin =1:1:(kol_int)
cc_sin =1:1:(kol_int)
xx1=0
yy1=1
for ii=1:1:kol_int
xx2=xx1+step
yy2=cos(xx2)
wsp1 =(yy2-yy1)/(xx2-xx1) /// наклон
xx3=asin(-wsp1) /// координаты центральной точки
yy3= sqrt( 1- wsp1^2) /// cos(xx3)
[aa,bb,cc]=koef_parabola( xx1,yy1,xx2,yy2,xx3,yy3)
aa_sin(ii)=aa
bb_sin(ii)=bb
cc_sin(ii)=cc
xx1=xx2
yy1=yy2
end
///вывод шага и коэффициентов
disp( step,aa_sin,bb_sin,cc_sin)
xx1=0
xx2=step
for ii=1:1:kol_int
int01=[xx1:0.005:xx2]
a1=aa_sin(ii)
b1=bb_sin(ii)
c1=cc_sin(ii)
plot(int01, (cos(int01) - a1*int01^2 -b1*int01-c1 ) )
xx1=xx1+step
xx2=xx2+step
end
Пример отклонений для синуса
график отклонений полинома второй степени от синуса на интервале 0 ... Пи/ 2 при разбиении на 8 интервалов ( размер интервала =Пи/ 16 примерно = 0.196 )
Расчет коэффициентов для косинуса на Scilab
function [a, b, c]=koef_parabola(x1, y1, x2, y2, x3, y3)
/// расчет коэффициентов параболы по 3 точкам
a1= y3 - ( x3*(y2-y1)+ x2*y1 -x1*y2 )/( x2-x1)
a2= x3*( x3-x1-x2 ) + x1*x2
a= a1 /a2
b =( y2-y1)/( x2-x1) - a*( x1+x2)
c=( x2*y1 - x1*y2) / (x2-x1) + a * x1*x2
endfunction
kol_int =12 /// количество интервалов на отрезке 0 ... %pi/ 2
kol_funct =kol_int+1
step =%pi/ ( 2kol_int) /// шаг
point0_x =0:step:%pi/ 2
point0_sin = cos(point0_x)
aa_sin =1:1:(kol_int)
bb_sin =1:1:(kol_int)
cc_sin =1:1:(kol_int)
xx1=0
yy1=1
for ii=1:1:kol_int
xx2=xx1+step
yy2=cos(xx2)
wsp1 =(yy2-yy1)/(xx2-xx1) /// наклон
xx3=asin(-wsp1) /// координаты центральной точки
yy3= sqrt( 1- wsp1^2) /// cos(xx3)
[aa,bb,cc]=koef_parabola( xx1,yy1,xx2,yy2,xx3,yy3)
aa_sin(ii)=aa
bb_sin(ii)=bb
cc_sin(ii)=cc
xx1=xx2
yy1=yy2
end
///вывод шага и коэффициентов
disp( step,aa_sin,bb_sin,cc_sin)
xx1=0
xx2=step
for ii=1:1:kol_int
int01=[xx1:0.005:xx2]
a1=aa_sin(ii)
b1=bb_sin(ii)
c1=cc_sin(ii)
plot(int01, (cos(int01) - a1*int01^2 -b1*int01-c1 ) )
xx1=xx1+step
xx2=xx2+step
end
Пример отклонений для косинуса
график отклонений полинома второй степени от синуса на интервале 0 ... Пи/ 2 при разбиении на 12 интервалов
Синус таблица коэффициентов полинома степени 2 для 8 интервалов
( шаг Пи / 16 )
Я не привожу кода на каком либо языке или псевдокода, дабы не засорять публикацию, каждый желающий может подобрать себе коэффициенты полинома степени 2 для аппроксимации и написать свою функцию. По значению аргумента x вычисляем номер интервала, запоминаем коэффициенты и подставляем из в формулу полинома
Комментарии (21)
Rsa97
03.03.2022 10:16+7Если нужно быстро и не очень точно, то есть старая добрая формула Бхаскара, работающая на отрезке от 0 до 180°.
SemenovVV Автор
03.03.2022 10:33а отрезка от 0 до 90° мало? + что проще считать? где больше делений и умножений?
unsignedchar
03.03.2022 10:46+2Это больше вопрос с индусу, который в 7 веке додумался до этой формулы;).
ЗЫ: нужна ли программисту математика за пределами школьной?
Rsa97
03.03.2022 11:02Отрезка 0-90°, конечно, достаточно, но формула симметрична относительно 90°.
А по вычислениям тут два вычитания, два умножения и деление.
SemenovVV Автор
03.03.2022 16:54если считать по предлагаемому мной способу, то всего на 6 интервалах точность вычисления синуса примерно в 10 раз выше чем по формуле Бхаскара. + по сложности (число делений и умножений ) как вычисление числителя. Снимаю шляпу перед Бхаскаром. Очень интересно, как он до своей формулы додумался?
Rsa97
03.03.2022 17:24+1У вас полином второй степени ax2+bx+c. Значит три умножения и два сложения.
y = x*x, y = a*y, z = b*x, z = z+y, z = z+c.
Столько же операций и в формуле Бхаскара, только там не надо искать интервал в таблице.
y = 180-x, y = y*x, z = 40500-y, y = y*4, y = y/z.
AVI-crak
03.03.2022 10:24Мк без математики, это как запорожец на соревнованиях формулы F1. Ну получили синус, а дальше-то что с ним делать? Оно конечно будет ехать, и даже с хорошей скоростью, но только по прямой линии. А чтобы проходить повороты - нужна математика.
https://github.com/AVI-crak/Rtos_cortex/blob/master/math_s.c#L356
Ktator
03.03.2022 10:57+3Целью данной публикации попытка предложить способ расчета синуса и косинуса достаточно быстро
Насколько быстро? Для вычисления синуса придумано огромное число разных алгоритмов приближения. Если вы предлагаете свой вариант, то он должен быть чем-то лучше, например, быстрее других при заданных точности и расходе памяти. А для этого нужны бенчмарки.Мне кажется, что выпуклые функции синус и косинус можно аппроксимировать ...
Математика – это точная наука, здесь не может ничего казаться. Как только вы определите критерии, сразу появится возможность будет вычислить, можно или нельзя.Я не привожу кода на каком либо языке или псевдокода, дабы не засорять публикацию
У вас публикация и так короткая, можно было бы и добавить (ну или хотя бы выложить на github). Не то, что это сложно или лично мне интересно, но просто глаз резануло от такого заявления.SemenovVV Автор
03.03.2022 11:26согласен, что математика точная наука. но фактически все наши вычисления с вещественными числами приближенные. код не привел т.к. он существенно зависит от требуемой точности вычислений и размера интервала (шага). А так достаточно просто, определили в какой интервал попадает аргумент, вытащили коэффициенты ( могут храниться в массиве ), вычислили полином степени 2.
Ktator
03.03.2022 11:46но фактически все наши вычисления с вещественными числами приближенные.
Не понял, к чему это. Я же не писал, что мы вычисляем что-то идеально точно.
Daemonis
03.03.2022 12:20+5Мне кажется, линейной функцией будет еще быстрее :)
ПС: а можно и константой 0.5 :) Так будет практически мгновенно и довольно точно :)
iboltaev
Кажется - это плохо.
Если нужно посчитать быстро и не очень точно, то лучше таблица + линейная интерполяция
SemenovVV Автор
так туже тоже самое, квадратичная интерполяция + можно подобрать требуемую точность размером интервала +вы пропустили слова не только ...
iboltaev
требуемую точность можно и размером таблицы подобрать