-
Всем привет. Требуется вычислить синус и косинус.
Формула известна: Sin A = X/Radius, Cos A = Y/Radius.
Отсюда вопрос: как получить величину X и Y, если известен только угол?
Тут картинка:
https://yadi.sk/i/UdcTmWDS3UDDGB
-
-
Мне надо понять откуда берутся формулы вроде Sqrt(2.0) / 2.0 = 0,7071067....
Как вычислить откуда взялась двойка и почему надо делить корень из двух на двойку при 45°, например.
-
>Если радиус неизвестен, то никак.
Радиус известен. Он равен единице.
На крайний случай можно взять любое простое число. Например 7.
-
Из того что углы по 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
-
Нагрузить сопроцессор?
Использовать любое разложение в ряд?
Завести таблицу готовых ответов?
-
-
Спс всем. Сделал через ряды Тейлора.
-
Просто интересно, а чем не угодили функции sin, cos и SinCos?
-
>Просто интересно, а чем не угодили функции sin, cos и SinCos?
Да всем угодили. Просто тему «поковырял». Стало интересно как сделать это без процессора. Оказывается можно.
-
> dmk © (11.04.18 09:06) [9]
> Стало интересно как сделать это без процессора. Оказывается можно.
Одно мне не понять: почему бы так сразу вопрос и не поставить? ;)
("без процессора" - это, конечно, не совсем удачная фраза, в вопросе если бы она была - то всё ушло бы не туда, аккуратнее тут бы надо.)
-
Кстати, вот такая штука еще есть, например:
...
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;
...
Угадайте, что за массив мы получим?
-
тангенс?
-
Вот например так можно:
//На входе угол в градусах, результат в радианах
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;
Функция не моя. Подсказали.
-
Теперь вот полиномами занимаюсь. Вариантов вычисления синуса и косинуса вагон и маленькая тележка. Думаю пока какой полином выбрать. Говорят полиномы Чебышёва самые точные в районе нуля.
-
> KilkennyCat © (11.04.18 23:35) [12]
>
> тангенс?
В данном случае массив синусов с шагом 0,01 (около 0,57 градуса)
-
> SergP © (12.04.18 00:19) [15]
эх,не угадал. я думал, что раз синусы и косинусы уже были, то вероятность тангенса высока )
-
> SergP © (12.04.18 00:19) [15]
и, кстати, спасибо. Пригодится.
-
> 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;
A[1]:=0.01;
k=1.9999;
-
> из-за нее амплитуда синусоиды уменьшается в 2 раза а частота
> увеличивается в 2 раза
именно это и нужно.
-
Во как еще синус считают:
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
-
> точность у нее всего 1e-2
ну. для некоторых решений более чем. иногда важнее быстрый и простой (незатратный по ресурсам) расчет.
-
Мне нужен точный расчет. 1e-14 и более. Не знакомы с методами?
-
> [22] dmk © (13.04.18 12:34)
> Мне нужен точный расчет
Ряды пробовал, не подходят, не предлагать. Так?
-
И ты думаешь сопроцессор вычисляет молитвой?
-
> dmk © (13.04.18 12:34) [22]
>
> Мне нужен точный расчет. 1e-14 и более. Не знакомы с методами?
>
Для быстрого и точного расчета есть сопроцессор.
Для познавательных целей есть ряды, цепные дроби и т.д.
А Вам для чего нужно?
-
>Ряды пробовал, не подходят, не предлагать. Так?
Ряды очень неточные. Их вообще лучше не использовать. Это приближенный метод.
Процессоры работают через CORDIC или полиномы Чебышёва.
-
>In the 1990s Intel replaced the 8087’s CORDIC-based approximations of the elementary
>transcendental functions with polynomial-based approximations.
Вот примерно так. Может и не Чебышев конечно. Вряд ли они раскажут.
-
>А Вам для чего нужно?
Чтобы было )
-
> [26] dmk © (13.04.18 14:12)
> Это приближенный метод.
Все методы приближённые. Ряды неточные так же как и всё остальное, потому что иррациаональные числа не представимы через целые, и с плавающей точкой, которые тоже целые по сути с некоторым усовершенствованием. Но могут быть вычеслены с любой точностью. В чём проблема? Остальное уже усовершенствования и оптимизация.
-
-
Возник тут в мозгу весьма интересный вариант как посчитать синус, но судя по всему он не будет быстрым...
Но если нужно для наглядности, могу попробовать эту мысль преобразовать в код на Delphi.
-
Вот что получилось
Аргумент передается в виде целого числа, размерность которого определяется первоначальными присвоениями значений 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
-
Пока будет считать CPU:
function Cos(A: PDouble): Double;
asm
fld qword ptr [A]
fcos
fstp qword ptr [Result]
end;
Точности хватает.
-
> [33] dmk © (14.04.18 03:05)
> Пока будет считать CPU:
Ты в который раз про процессор и всё время что-то не то. Может быть, ты хотел написать "FPU"?
И про точность тоже не ясно, я же выше написал - с любой точностью. Понятно, что надо арифметику расширенную до нужной точности сделать.
-
>Может быть, ты хотел написать "FPU"?
FPU находится в CPU ...
Каламбур© ;)
-
Хотя помню для 386DLC покупали отдельный сопроцессор Cyrix.
Получался 386DX-40 ;)
-
> [36] dmk © (14.04.18 12:11)
Плохо помнишь.
-
Грубо говоря CPU и FPU склеили вместе - но всё равно это разные системы, термины "процессор" и "сопроцессор" разные, и команды у них разные. FCOS - это команда сопроцессора (FPU).
Всё же рассмотрите команду FSINCOS.
-
если говорить про алгоритмы, то упоминать о какихто склеенных фпу нетолератно по отношению к другим процессорам, например, PIC10F200
-
Пока сделал так:
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.
Есть у кого опыт с обработкой исключений?
-
-
Спасибо, интересно!
Только надо было музычку забахать, чё в тишине-то всё)))
https://www.youtube.com/watch?v=DT61L8hbbJ4А шарик всем шарикам шарик! Как такой называется кстати?
И всё же вы пробовали делать через таблицу уже посчитанных значений?
-