Мастера DELPHI, Delphi programming community Рейтинг@Mail.ru Титульная страница Поиск, карта сайта Написать письмо 
| Новости |
Новости сайта
Поиск |
Поиск по лучшим сайтам о Delphi
FAQ |
Огромная база часто задаваемых вопросов и, конечно же, ответы к ним ;)
Статьи |
Подборка статей на самые разные темы. Все о DELPHI
Книги |
Новинки книжного рынка
Новости VCL
Обзор свежих компонент со всего мира, по-русски!
|
| Форумы
Здесь вы можете задать свой вопрос и наверняка получите ответ
| ЧАТ |
Место для общения :)
Орешник
Коллекция курьезных вопросов из форумов
Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / rsdn.org

 
Чтобы не потерять эту дискуссию, сделайте закладку « предыдущая ветвь | форум | следующая ветвь »

Вычислить синус и косинус


dmk ©   (08.04.18 15:03

Всем привет. Требуется вычислить синус и косинус.
Формула известна: Sin A = X/Radius, Cos A = Y/Radius.
Отсюда вопрос: как получить величину X и Y, если известен только угол?
Тут картинка: https://yadi.sk/i/UdcTmWDS3UDDGB


Pavia ©   (08.04.18 15:28[1]

Если радиус неизвестен, то никак.
Radius Sin A = X
Radius Cos A = Y

А если нужно вычислить Sin A =  и Cos A =
то надо использовать ряд Тейлора.
https://ru.wikipedia.org/wiki/Тригонометрические_функции


dmk ©   (08.04.18 16:03[2]

Мне надо понять откуда берутся формулы вроде Sqrt(2.0) / 2.0 = 0,7071067....
Как вычислить откуда взялась двойка и почему надо делить корень из двух на двойку при 45°, например.


dmk ©   (08.04.18 16:04[3]

>Если радиус неизвестен, то никак.
Радиус известен. Он равен единице.
На крайний случай можно взять любое простое число. Например 7.


Pavia ©   (08.04.18 16:24[4]

Из того что углы по 45  следует что X=Y
Из теоеремы пирфогора R=sqrt(x^+y^2)
Тогда sin A=X/R=X/sqrt(x^+y^2)
X/sqrt(2X^2)=x/{sqrt(2)x}=1/sqrt(2)
домножаем на sqrt(2) числитель и знаменатель
sqrt(2)/2


Redmond   (08.04.18 16:29[5]

Нагрузить сопроцессор?
Использовать любое разложение в ряд?
Завести таблицу готовых ответов?


Pavia ©   (08.04.18 17:04[6]

А углы 30 и 60 есть в учебнике за 8 класс
https://interneturok.ru/geometry/8-klass/podobnye-treugolniki/znachenie-sinusa-kosinusa-i-tangensa-dlya-uglov-30-45-i-60-gradusov


dmk ©   (08.04.18 21:29[7]

Спс всем. Сделал через ряды Тейлора.


Dimka Maslov ©   (10.04.18 23:29[8]

Просто интересно, а чем не угодили функции sin, cos и SinCos?


dmk ©   (11.04.18 09:06[9]

>Просто интересно, а чем не угодили функции sin, cos и SinCos?
Да всем угодили. Просто тему «поковырял». Стало интересно как сделать это без процессора. Оказывается можно.


KSergey ©   (11.04.18 11:24[10]

> dmk ©   (11.04.18 09:06) [9]
> Стало интересно как сделать это без процессора. Оказывается можно.

Одно мне не понять: почему бы так сразу вопрос и не поставить? ;)

("без процессора" - это, конечно, не совсем удачная фраза, в вопросе если бы она была - то всё ушло бы не туда, аккуратнее тут бы надо.)


SergP ©   (11.04.18 23:08[11]

Кстати, вот такая штука еще есть, например:

...
var
 a:array[0..200] of extended;

implementation

procedure FillArr;
var
k:extended;
i:integer;
begin
a[0]:=0;
a[1]:=0.01;
k:=1.9996;
for i:=2 to 200 do a[i]:=k*a[i-1]-a[i-2];
end;
...


Угадайте, что за массив мы получим?


KilkennyCat ©   (11.04.18 23:35[12]

тангенс?


dmk ©   (11.04.18 23:40[13]

Вот например так можно:

//На входе угол в градусах, результат в радианах
function Sin_Taylor(X: Double): Double;
const
 OneD: Double = 100000000000000.0; //14 разрядов точности
 OneM: Double = 0.00000000000001;

var
 N: Integer;
 sqrX, Cur, Ret: Double;
 K, K2: Integer;
 radX: Double;

begin
 Ret := 0.0;
 radX := NormalizeAngle(X) * DegToRadD;

 N := 10 + 2 * Abs(Trunc(radX));
 radX := TruncD(OneD * radX);
 Cur := radX;
 SQRX := (radX * radX);

 for K := 0 to N do
 begin
   Ret := (Ret + Cur);
   K2 := (K shl 1);
   Cur := FloorDiv(-Cur * SQRX, (K2 + 2) * (K2 + 3) * OneD * OneD);
 end;

 Result := (Ret * OneM);
end;

//На входе угол в градусах, результат в радианах
function Cos_Taylor(X: Double): Double;
const
 Epsilon: Double = 0.00000000000001;

begin
 Result := Sin_Taylor(NormalizeAngle(X) - 90.0);
 if Abs(Result) <= Epsilon then Result := 0.0;
end;


Функция не моя. Подсказали.


dmk ©   (11.04.18 23:42[14]

Теперь вот полиномами занимаюсь. Вариантов вычисления синуса и косинуса вагон и маленькая тележка. Думаю пока какой полином выбрать. Говорят полиномы Чебышёва самые точные в районе нуля.


SergP ©   (12.04.18 00:19[15]


> KilkennyCat ©   (11.04.18 23:35) [12]
>
> тангенс?


В данном случае массив синусов с шагом 0,01 (около 0,57 градуса)


KilkennyCat ©   (12.04.18 00:36[16]


> SergP ©   (12.04.18 00:19) [15]

эх,не угадал. я думал, что раз синусы и косинусы уже были, то вероятность тангенса высока )


kilkennycat ©   (12.04.18 00:38[17]


> SergP ©   (12.04.18 00:19) [15]

и, кстати, спасибо. Пригодится.


SergP ©   (12.04.18 10:58[18]


> kilkennycat ©   (12.04.18 00:38) [17]
>
>
> > SergP ©   (12.04.18 00:19) [15]
>
> и, кстати, спасибо. Пригодится.


Кстати, тут небольшая ошибочка (из-за нее амплитуда синусоиды уменьшается в 2 раза а частота увеличивается в 2 раза):

>  k:=1.9996;

при шаге 0,01 оно должно быть равным 1,9999

A[0]:=0;       // sin(0)=0
A[1]:=0.01;   // Берем шаг delta=0.01, A[1]:=sin(delta), а учитывая первый замечательный предел sin(0.01)~0.01
k=1.9999;   //k:=2*cos(delta) или k:=2*sqrt(1-delta*delta)


kilkennycat ©   (12.04.18 15:37[19]


> из-за нее амплитуда синусоиды уменьшается в 2 раза а частота
> увеличивается в 2 раза

именно это и нужно.


dmk ©   (12.04.18 20:12[20]

Во как еще синус считают:

function Sin_APX(X: Double): Double;
begin
 X := X / (2.0 * PI);
 X := X - Round(X);
 X := X * 7.59 * (0.5 - Abs(X));
 Result := (1.634 + Abs(X)) * X;
end;


Но точность у нее всего 1e-2. На 3-м знаке уже расхождение.
Тут онлайн компилято посмотреть:
http://rextester.com/DALIFZ95838


kilkennycat ©   (13.04.18 03:45[21]


>  точность у нее всего 1e-2

ну. для некоторых решений более чем. иногда важнее быстрый и простой (незатратный по ресурсам) расчет.


dmk ©   (13.04.18 12:34[22]

Мне нужен точный расчет. 1e-14 и более. Не знакомы с методами?


Inovet ©   (13.04.18 13:46[23]

> [22] dmk ©   (13.04.18 12:34)
> Мне нужен точный расчет

Ряды пробовал, не подходят, не предлагать. Так?


Inovet ©   (13.04.18 13:48[24]

И ты думаешь сопроцессор вычисляет молитвой?


SergP ©   (13.04.18 14:10[25]


> dmk ©   (13.04.18 12:34) [22]
>
> Мне нужен точный расчет. 1e-14 и более. Не знакомы с методами?
>


Для быстрого и точного расчета есть сопроцессор.
Для познавательных целей есть ряды, цепные дроби и т.д.
А Вам для чего нужно?


dmk ©   (13.04.18 14:12[26]

>Ряды пробовал, не подходят, не предлагать. Так?
Ряды очень неточные. Их вообще лучше не использовать. Это приближенный метод.

Процессоры работают через CORDIC или полиномы Чебышёва.


dmk ©   (13.04.18 14:31[27]

>In the 1990s Intel replaced the 8087’s CORDIC-based approximations of the elementary
>transcendental functions with polynomial-based approximations.

Вот примерно так. Может и не Чебышев конечно. Вряд ли они раскажут.


dmk ©   (13.04.18 14:40[28]

>А Вам для чего нужно?
Чтобы было )


Inovet ©   (13.04.18 14:51[29]

> [26] dmk ©   (13.04.18 14:12)
> Это приближенный метод.

Все методы приближённые. Ряды неточные так же как и всё остальное, потому что иррациаональные числа не представимы через целые, и с плавающей точкой, которые тоже целые по сути с некоторым усовершенствованием. Но могут быть вычеслены с любой точностью. В чём проблема? Остальное уже усовершенствования и оптимизация.


Redmond   (13.04.18 18:46[30]

Вы уверены? Подобная точность требуется менее чем в 0.25% случаев.
А по поводу оптимизаций - сопроцессор если что уметь одновременное вычисление значения синуса и косинуса.
И ещё вот: https://stackoverflow.com/questions/2683588/what-is-the-fastest-way-to-compute-sin-and-cos-together


SergP ©   (13.04.18 19:06[31]

Возник тут в мозгу весьма интересный вариант как посчитать синус, но судя по всему он не будет быстрым...

Но если нужно для наглядности, могу попробовать эту мысль преобразовать в код на Delphi.


SergP ©   (13.04.18 20:04[32]

Вот что получилось
Аргумент передается в виде целого числа, размерность которого определяется первоначальными присвоениями значений sn и сs

Допустим мы передаем на вход функции кол-во тысячных долей радиан, тогда:
sn:=sin(0.001)
cs:=cos(0.001)

ну и аргумент должен быть >=0, иначе нужно доработать код учитывая нечетность функции синуса

function sinus(source:integer):extended;
var
 sn,cs,sres,cres:extended;
begin
 sn:=0.000999999833333341666666468253971;
 cs:=0.99999950000004166666527777780258;
 Result:=0;
 cres:=1;
 while source>0 do
 begin
   if source and 1 = 1 then
   begin
     sres:=Result;
     Result:=sres*cs+cres*sn;
     cres:=cres*cs-sres*sn;
   end;
   sn:=2*sn*cs;
   cs:=2*cs*cs-1;
   source:=source shr 1;
 end;
end;


Количество итераций цикла равно количеству значащих двоичных разрядов аргумента.
Сверялся с калькулятором. Точность довольно неплохая.
Например значение функции при аргументе 100000 (т.е. 100 радиан) равно -0,506365641097155
А калькулятор говорит что:
-0,50636564110975879365655761045979


dmk ©   (14.04.18 03:05[33]

Пока будет считать CPU:

function Cos(A: PDouble): Double;
asm
 fld qword ptr [A]
 fcos
 fstp qword ptr [Result]
end;


Точности хватает.


Inovet ©   (14.04.18 07:31[34]

> [33] dmk ©   (14.04.18 03:05)
> Пока будет считать CPU:

Ты в который раз про процессор и всё время что-то не то. Может быть, ты хотел написать "FPU"?

И про точность тоже не ясно, я же выше написал - с любой точностью. Понятно, что надо арифметику расширенную до нужной точности сделать.


dmk ©   (14.04.18 12:08[35]

>Может быть, ты хотел написать "FPU"?

FPU находится в CPU ...
Каламбур© ;)


dmk ©   (14.04.18 12:11[36]

Хотя помню для 386DLC покупали отдельный сопроцессор Cyrix.
Получался 386DX-40 ;)


Inovet ©   (14.04.18 12:18[37]

> [36] dmk ©   (14.04.18 12:11)

Плохо помнишь.


Redmond   (14.04.18 14:42[38]

Грубо говоря CPU и FPU склеили вместе - но всё равно это разные системы, термины "процессор" и "сопроцессор" разные, и команды у них разные. FCOS - это команда сопроцессора (FPU).

Всё же рассмотрите команду FSINCOS.


KilkennyCat ©   (14.04.18 19:55[39]

если говорить про алгоритмы, то упоминать о какихто склеенных фпу нетолератно по отношению к другим процессорам, например, PIC10F200


dmk ©   (15.04.18 12:09[40]

Пока сделал так:
function _Cos(A: PDouble): Double;
asm
 .NOFRAME

 fld qword ptr [A]
 fcos
 fstp qword ptr [Result]
end;

function _Sin(A: PDouble): Double;
asm
 .NOFRAME

 fld qword ptr [A]
 fsin
 fstp qword ptr [Result]
end;

Работает, но нужно обрабатывать исключения. Часто выдает -1,#IND.
Есть у кого опыт с обработкой исключений?


dmk ©   (27.02.19 11:12[41]

Написал. Если кому интересно, то вот готовые функции:
https://habr.com/ru/post/429786/


Лори   (01.03.19 14:13[42]

Спасибо, интересно!
Только надо было музычку забахать, чё в тишине-то всё))) https://www.youtube.com/watch?v=DT61L8hbbJ4
А шарик всем шарикам шарик! Как такой называется кстати?

И всё же вы пробовали делать через таблицу уже посчитанных значений?


dmk ©   (01.03.19 20:59[43]

>И всё же вы пробовали делать через таблицу уже посчитанных значений?
Вы не поверите, но у меня все работает через таблицы (практически Брадиса), а значения вычисляются своей функцией.

Fat Rat - это тонкий намек? Если да, то я ничего не украл. Сам все пишу.
Музычка так себе. Мне эта больше нравится: https://www.youtube.com/watch?v=aah-CxW54pw&index=10&list=PL4E2wb3zTeuWShm9Jro6XbDfxc_758CYZ&t=0s


версия для печати

Написать ответ

Ваше имя (регистрация  E-mail 







Разрешается использование тегов форматирования текста:
<b>жирный</b> <i>наклонный</i> <u>подчеркнутый</u>,
а для выделения текста программ, используйте <code> ... </code>
и не забывайте закрывать теги! </b></i></u></code> :)


Наверх

  Рейтинг@Mail.ru     Титульная страница Поиск, карта сайта Написать письмо