Консультация № 197492
24.12.2019, 22:20
0.00 руб.
0 9 1
Здравствуйте, уважаемые эксперты! Прошу вас ответить на следующий вопрос: как средствами JavaScript реализовать расчёт тригонометрических функций Sin и Cos угла без использования Math?

Обсуждение

давно
Модератор
137394
1850
24.12.2019, 22:33
общий
24.12.2019, 23:46
Адресаты:
А с какой точностью и зачем это нужно? Например, есть алгоритм, там есть ссылка на более подробную статью. По этой формуле Бхаскара, по использованию стандартной функции, погрешность по отношению к стандартному методу %:
Код:
var S;
S=mysin(1);
S=mysin(30);
S=mysin(45);
S=mysin(60);
S=mysin(90);

function mysin(x) {
var S1,S2;
S1=4*x*(180-x)/(40500-x*(180-x));
S2=Math.sin(x*Math.PI/180);
WScript.Echo(x+"\n"+S1+"\n"+S2+"\n"+Math.abs(100*(S1-S2)/S2));
}
Получаем до 2% погрешности для приведенных значений.

Вот еще: Какой алгоритм вычисления sin или cos используется в современных языках?
Любое переписывание стандартной функции - плохая идея.
Об авторе:
Понеже не словес красных бог слушает, но дел наших хощет
давно
Мастер-Эксперт
259041
7459
25.12.2019, 12:07
общий
25.12.2019, 12:08
Адресаты:
Вы не сообщили, в какой среде выполняется Ваш JavaScript ? Если он работает не в браузере (с жёсткими ограничениями), а в Windows или в HTA-приложениях Ссылка , то из него можно вызывать VBS-функции, в тч тригонометрические, вычисляющие с высокой точностью.
давно
Модератор
137394
1850
27.12.2019, 16:28
общий
это ответ
Здравствуйте, Мироненко Николай Николаевич!
В Вашей постановке вопроса однозначно ответить нельзя: всё зависит от того, зачем это нужно: с какой точностью Вам необходимо иметь результат и насколько критично время вычисления функции с этой точностью, в каком диапазоне аргументов требуется вычислять функцию.
Наверное, имеет смысл рассуждать о значении sin в диапазоне от 0 до Pi/2 (0-90 градусов), а sin для аргументов вне этого диапазона и cos вычисляются школьными формулами приведения.
Этот вопрос обсуждался, например, здесь: Какой алгоритм вычисления sin или cos используется в современных языках?
Возможен вариант определения массива со значениями sin для дискретного значения аргументов с последующей интерполяцией промежуточных значений.
Можно поискать формулы для приближенного вычисления. Например, формула Бхаскара для аргументов 0-180 градусов, то есть 0-Pi.


В мини-форуме этого вопроса я привёл сравнение вычисления sin по этой формуле и стандартной функции. Если устраивает погрешность ~2% (в худшем случае), вполне доступный способ.

5
Об авторе:
Понеже не словес красных бог слушает, но дел наших хощет
давно
Академик
20764
1861
27.12.2019, 18:44
общий
Насколько я знаю, все функции вычисляются одинаково: аргумент приводится к фиксированному отрезку и на этом отрезке аппроксимируется с нужной точностью полиномом Чебышева или цепной дробью
давно
Мастер-Эксперт
259041
7459
28.12.2019, 02:31
общий
Адресаты:
Если сравнивать похожие языки JavaScript и VBScript , то у них набор функций отличается. А поскольку комплектация и синтаксис функций отличается, то я очень сомневаюсь в том, что "все функции вычисляются одинаково".

Только автору Вопроса это не нужно, он создал Косультацию и сбежал, 3 суток не посещает Портал. Он даже Ответ на читал.
Нужна ли Активность экспертов при таком наплевательском отношении авторов вопросов к нашим стараниям и к своим халявным Вопросам? - вот в чём проблема rfpro.ru .
давно
Академик
20764
1861
28.12.2019, 11:39
общий
Адресаты:

они же не сами эти синусы вычисляют! Используют библиотеку нижнего уровня. В *NIX это libm
давно
Мастер-Эксперт
259041
7459
28.12.2019, 12:21
общий
Адресаты:
До *NIX-ов я в этой жизни уже не доберусь. А точность вычисления синусов скриптами проверю на досуге. Мы то знаем точный ответ , что sin(60°)=[$8730$](3)/2 , а скрипты вряд ли делают исключения для "круглых" аргументов и вычисляют полиномами. Надо придумать, как вынудить их выводить на экран побольше значащих цифр, а то в округлённых ответах с 3мя знаками их погрешность вероятно будет незаметна. Умножить ответы на 1000 ?
давно
Модератор
137394
1850
30.12.2019, 21:17
общий
30.12.2019, 21:24
Адресаты:
Попробовал элементарное разложение Sin в ряд Тэйлора:

Нарисовал тестовую функцию mysin. В аргументе x- угол градусов (сделал в градусах для наглядности), N- число членов ряда.
Код:
var arg,argr,M,Rez;

Rez="";
M=3; arg=1; argr=arg*1.7453292519943295E-02; Rez=Rez + "\n" + arg + "\n" + mysin(arg,M) + "\n" + Math.sin(argr) + "\n" + Math.abs(100*(mysin(arg,M)-Math.sin(argr))/Math.sin(argr))+"%"+"\n\n";
M=3; arg=30; argr=arg*1.7453292519943295E-02; Rez=Rez + "\n" + arg + "\n" + mysin(arg,M) + "\n" + Math.sin(argr) + "\n" + Math.abs(100*(mysin(arg,M)-Math.sin(argr))/Math.sin(argr))+"%"+"\n\n";
M=3; arg=60; argr=arg*1.7453292519943295E-02; Rez=Rez + "\n" + arg + "\n" + mysin(arg,M) + "\n" + Math.sin(argr) + "\n" + Math.abs(100*(mysin(arg,M)-Math.sin(argr))/Math.sin(argr))+"%"+"\n\n";
M=3; arg=90; argr=arg*1.7453292519943295E-02; Rez=Rez + "\n" + arg + "\n" + mysin(arg,M) + "\n" + Math.sin(argr) + "\n" + Math.abs(100*(mysin(arg,M)-Math.sin(argr))/Math.sin(argr))+"%"+"\n\n";

WScript.Echo(Rez);

function mysin(x,N) {
var S=x*1.7453292519943295E-02;
var S1=S;
var SS=S*S;
for (var i=3; i<=2*N-1; i=i+2) {S1=-S1*SS/((i-1)*i);S=S+S1}
return S;
}
Отображаю: градусы, результат по тестовой функции, результат стандартной функции, относительная погрешность %
В указанном диапазоне погрешность менее полпроцента, однако для трёх членов ряда время вычисления в 1.7 раз больше, чем по формуле Бхаскара, в свою очередь стандартная функция в 1,3 считает быстрее этой формулы.
Так что возвращаемся к вопросу: какая точность допустима и как критично время вычисления.
Об авторе:
Понеже не словес красных бог слушает, но дел наших хощет
давно
Мастер-Эксперт
259041
7459
02.01.2020, 02:40
общий
Начало Нового года я посвятил изучению особенностей JavaScript и сформировал 3 сравнительные таблицы погрешностей вычисления синусов. Погрешности оказались столь малы, что для вывода на экран их НЕ-обнулённых значений пришлось умножать значения вычисленных синусов даже не на 1000, а на 10^15 ! И притом умножать КАЖДОЕ синус-значение (эталона и полиномного) до того, как будет вычислена их мизерная разность.

Совпадение результирующих погрешностей (прилагаю скриншот) очень удивили меня, потому что синтаксисы программных языков JavaScript и VBScript существенно отличаются. Например, VBScript (в отличии от JS) не имеет встроенной функции получения числа Пи , приходится получать точное Пи-значение окольным путём ч-з арктангенс
Pi=4*Atn(1)

Зато JavaScript не понимает стандартный оператор возведения в степень типа 10^15 , не умеет округлять до требуемого числа знаков после запятой, а бОльшую часть мат-операций приходится дописывать префикс "Math." . Например, чтоб получить "Синус угла 60° = 0.866" (с 3мя знаками после запятой) приходится городить
sin60 = Math.round(Math.sin(60 * Math.PI / 180) * 1000) / 1000;

Сравнительно недавно в JavaScript-синтаксис добавили оператор возведения в степень в странном виде
10 ** 15
а также удобный метод округления toPrecision() Ссылка . Но эти методы работают т-ко в среде современных браузеров, моя любимая ОперСистема WindowsXP не понимает их.

В общем, выходит, что уважаемый эксперт Хватов Сергей оказался прав "все функции вычисляются одинаково … Используют библиотеку нижнего уровня". Это подтверждают и посты в статье по ссылке в Ответе не менее уважаемого эксперта Megaloman .

Скрипты и Маткад вычисляют синусы/косинусы в миллиарды раз точнее, чем формула Бхаскара, поэтому у меня возникло подозрение, будто автор Вопроса не имеет претензий к использованию Math , просто ему захотелось как-то упростить код, чтобы избавить его от нудно-частого употребления префикса "Math." . Для оптимизации кода есть удобный оператор with() . Например
with(Math){
[Блок мат-вычислений]
}
позволяет в большом блоке мат-вычислений использовать тригонометрич, округляющие и проч мат-функции БЕЗ дописки префикса Math.
Форма ответа