LINUX.ORG.RU

вычисление тригонометрии - как?! как вы это делаете?

 ,


1

4

собственно вопрос. Я ни разу не программист, но тут что-то наткнулся на одно старое обсуждение тыц и у меня возник вопрос - собственно как это всё происходит.

Интересует сам механизм, достал свой пыльный конспект по матану всю ночь читал, пытался вспомнить, под утро наиндусил на C разложение в ряд Тейлора(в три итерации) и сравнил выхлоп с системной функцией... и вот вопрос таки возник.

Получилось, что на малых углах разбег начинается после второго знака, но уже к 30° он перескакивает на первый и далее только растёт. Оно понятно что я тот ещё индус, но хотелось бы послушать опыт знающих.(glibc я конечно почитаю потом).

конечный результат системного   косинуса  10:   0.984808
конечный результат вычисленного косинуса  10:   0.984731

конечный результат системного   косинуса  20:   0.939693
конечный результат вычисленного косинуса  20:   0.938460

конечный результат системного   косинуса  30:   0.866025
конечный результат вычисленного косинуса  30:   0.859819

сам код :

#include <stdio.h>
#include <math.h>
#define PI 3.14159265
double  rezult, deg_0,deg,test;
double factor (double iterration);
double stepen (double deg, double step);
double prom( double st, double faktor);
int main()
{
    printf ("введите значение: ");
    scanf("%lf", &deg_0);
    deg=deg_0*(PI/180);
    printf(" \n");
    printf("Processing... \n");
    double q;
    q=2;
    double promt;
    promt=prom(deg,q);
    q=q+2;
    promt=promt+prom(deg,q);
    q=q+2;
    promt=promt-prom(deg,q);
    q=q+2;
    promt=promt+prom(deg,q);
    rezult=1-promt;
    test=cos(deg);
    printf("конечный результат системного   косинуса %10f: %10f\n",deg_0, test);
    printf("конечный результат вычисленного косинуса %10f: %10f\n",deg_0, rezult);
    return 0;
}
double factor (double iterration)
{
    if(iterration < 0)
        return 0;
    if (iterration == 0)
        return 1;
    else
        return (iterration < 2) ? 1 : iterration * factor(iterration - 1);
}

double stepen (double deg, double step)
{
    if(step < 0) step = -step;
    if(step == 0) step = 1;
    double result = 1;
    for (double i = 0; i < step; i++) {
        result *= deg;
    }
    return result;
}
double prom(double st, double faktor)
{
 double znachenie;
  double i,j;
  i=stepen(st,faktor);
  j=factor(faktor);
  znachenie=i/j;
  return znachenie;
}
за код прошу сильно не пинать, я не программер, наиндусил на коленке чтоб проверить сам принцип.

Короче кто как это решает?

PS. интересует именно голый алгоритм,за системные инструменты glibc я в курсе.

★★

Последнее исправление: Gramozeka (всего исправлений: 1)

Ответ на: комментарий от Gramozeka

ты сделал мой день!))).

Дедушка, зачем вы прикинулись студентом? Захотелось вновь почувствовать себя молодым?:)

«как это делается»

Для начала это делается с нормальным значением PI, а не тем ужасом, что у тебя в коде. А потом уже идёт всяких дроч с погрешностями double и прочими численными методами.

crutch_master ★★★★★
()
Ответ на: комментарий от crutch_master

Дедушка, зачем вы прикинулись студентом? Захотелось вновь почувствовать себя молодым?:)

внучок, пять звёзд надрочил, а понимать написанное(кто сказал читать?!) ниасилил... пичалька.(

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

/*__улыбающаяся и восторженная рожа Якубовича__*/ пример в студию!

Дедушка, зачем вы прикинулись студентом? Захотелось вновь почувствовать себя молодым?:)

внучок, пять звёзд надрочил, а понимать написанное(кто сказал читать?!) ниасилил... пичалька.(

перечитай ещё раз что написано в стартовом посте.

PS... /*старческое брюзжание*/

а мы потом удивляемся засилию потеригоподобного индусского годвнокода, который notabug, а каждое обновление ломает всё, в том числе и предыдущую версию самого себя... они просто читать\понимать_прочитанное не обучены, лишь бы ляпнуть, поколение первонахов мля!

Gramozeka ★★
() автор топика
Последнее исправление: Gramozeka (всего исправлений: 1)
Ответ на: комментарий от Gramozeka

пример в студию!

Так вот же:

#define PI 3.14159265358979323846
Хотя это всё равно не поможет.
Ряд не работает как надо, потому что в каждом члене ряда делитель стремится в потолок, а значение к нулю. В итоге он быстро выходит за допустимый диапазон и проц. начинает греть воздух. При реализации используют всякие таблицы, коэффициенты и костыли, чтобы это хоть как-то посчиталось дальше 3-го члена ряда с минимальными потерями точности.
Впрочем, если хочется секаса можно попробовать сделать через какой-нибудь сишный bignumber или рациональные числа, но, конечно, это будет намного тормознее и с примерно тем же результатом.

crutch_master ★★★★★
()
Последнее исправление: crutch_master (всего исправлений: 1)
Ответ на: комментарий от Gramozeka

PS... /*старческое брюзжание*/

Нельзя просто так запостить говнокод на си и чтобы тебе про это ничего не сказали. Тебе еще повезло, что Царь этого не видит.

crutch_master ★★★★★
()
Последнее исправление: crutch_master (всего исправлений: 1)
Ответ на: комментарий от crutch_master

Так вот же:

Специально для вас в файле math.h есть много чего, не только пи.

/* Some useful constants.  */
#if defined __USE_MISC || defined __USE_XOPEN
# define M_E            2.7182818284590452354   /* e */
# define M_LOG2E        1.4426950408889634074   /* log_2 e */
# define M_LOG10E       0.43429448190325182765  /* log_10 e */
# define M_LN2          0.69314718055994530942  /* log_e 2 */
# define M_LN10         2.30258509299404568402  /* log_e 10 */
# define M_PI           3.14159265358979323846  /* pi */
# define M_PI_2         1.57079632679489661923  /* pi/2 */
# define M_PI_4         0.78539816339744830962  /* pi/4 */
# define M_1_PI         0.31830988618379067154  /* 1/pi */
# define M_2_PI         0.63661977236758134308  /* 2/pi */
# define M_2_SQRTPI     1.12837916709551257390  /* 2/sqrt(pi) */
# define M_SQRT2        1.41421356237309504880  /* sqrt(2) */
# define M_SQRT1_2      0.70710678118654752440  /* 1/sqrt(2) */
#endif

/* The above constants are not adequate for computation using `long double's.
   Therefore we provide as an extension constants with similar names as a
   GNU extension.  Provide enough digits for the 128-bit IEEE quad.  */
#ifdef __USE_GNU
# define M_El           2.718281828459045235360287471352662498L /* e */
# define M_LOG2El       1.442695040888963407359924681001892137L /* log_2 e */
# define M_LOG10El      0.434294481903251827651128918916605082L /* log_10 e */
# define M_LN2l         0.693147180559945309417232121458176568L /* log_e 2 */
# define M_LN10l        2.302585092994045684017991454684364208L /* log_e 10 */
# define M_PIl          3.141592653589793238462643383279502884L /* pi */
# define M_PI_2l        1.570796326794896619231321691639751442L /* pi/2 */
# define M_PI_4l        0.785398163397448309615660845819875721L /* pi/4 */
# define M_1_PIl        0.318309886183790671537767526745028724L /* 1/pi */
# define M_2_PIl        0.636619772367581343075535053490057448L /* 2/pi */
# define M_2_SQRTPIl    1.128379167095512573896158903121545172L /* 2/sqrt(pi) */
# define M_SQRT2l       1.414213562373095048801688724209698079L /* sqrt(2) */
# define M_SQRT1_2l     0.707106781186547524400844362104849039L /* 1/sqrt(2) */
#endif

akk ★★★★★
()
Ответ на: комментарий от crutch_master

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

Что за чушь я только что прочитал? Открой учебник мат. анализа и прочитай всё.

Всё работает идеально, совпадаёт с синусами/косинусами из стандартной библиотеки:

function no_standard_sin(x: double): double;
const
  eps:double = 1e-7;
var
  t, n: double;
begin
  result := x;
  t := x;
  n := 2;
  repeat
    t := -t * sqr(x)/(n*(n+1));
    result := result + t;
    n := n + 2;
  until abs(t) < eps;
end;

function no_standard_cos(x: double): double;
const
  eps:double = 1e-7;
var
  t, n: double;
begin
  result := 1;
  t := 1;
  n := 1;
  repeat
    t := -t * sqr(x)/(n*(n+1));
    result := result + t;
    n := n + 2;
  until abs(t) < eps;
end;

Вот проверил косинус от 0 до 2pi с шагом pi/12:

https://imgur.com/a/m5b7JyC

Синус проверял в прошлом посте.

fsb4000 ★★★★★
()
Последнее исправление: fsb4000 (всего исправлений: 1)
Ответ на: комментарий от fsb4000

Всё работает идеально

Да. Потому что у тебя ряд один, а у ТСа другой. Он там колхозил факториал со степенью, а у тебя этого ничего нет.

crutch_master ★★★★★
()
Последнее исправление: crutch_master (всего исправлений: 1)
Ответ на: комментарий от crutch_master

Нельзя просто так запостить говнокод на си и чтобы тебе про это ничего не сказали.

идея с пониманием прочитанного остаётся актуальной.)) Я создал тред не для показать свой индусский код(в который я не рублю особо, о чём честно и сказал), а узнать как люди это решают в обычной жизни.

Уже давно я собираю себе дистрибутив сам, из говна и палок из исходников, и поверь, довольно часто приходится в них погружаться надолго с головой, поэтому как выглядят тексты glibc или какой ещё системной приблуды я в курсе...

Мне интересен опыт живых, реальных кодеров(кому не жалко свои наработки светить). Вариантов написания одних и тех же «простейших» вещей море, но почему то, до сих пор народ пользуется корелами и арткамами(и прочими монстрами, вплоть до автокадов с бейсиковыми наростами) для генерации G-кодов(внезапно! векторная алгебра из первого курса!), неужели это так сложно? Вот этот тред показывает - что если и не сложно, то совсем не просто. А задай я вопрос прикладного характера? Так тут вообще все бы передрались?

Вроде и блендеры с критами и всякими инкскейпами понаписаны, и даже вроде как позиция «лучше не бывает»... а как надо профиль Сталина в 3D на роутере «по быстрому» отфрезеровать, так автокад и корел с арткамом наше всьо...))

Gramozeka ★★
() автор топика
Последнее исправление: Gramozeka (всего исправлений: 2)
Ответ на: комментарий от crutch_master

Он там колхозил факториал со степенью, а у тебя этого ничего нет.

Есть.

Возможно смутила функция sqr(x) - это функция в Паскале, которая возвращает квадрат x, то есть x*x.

Ряд Маклорена: https://imgur.com/a/VdgG2Jy

Следующий член суммы от предыдущего отличается в -1 * x * x /((n+1)*(n+2))

у меня: t := -t * sqr(x)/(n*(n+1));

Потому что я n начал с 1, а не с 0. Чтобы лишний раз не складывать.

если переписать так:

function no_standard_cos(x: double): double;
const
  eps:double = 1e-7;
var
  t, n: double;
begin
  result := 1;
  t := 1;
  n := 0;
  repeat
    t := -t * (x*x)/((n+1)*(n+2));
    result := result + t;
    n := n + 2;
  until abs(t) < eps;
end;

То

t := -t * (x*x)/((n+1)*(n+2));

будет один в один как в формуле

fsb4000 ★★★★★
()
Последнее исправление: fsb4000 (всего исправлений: 1)
Ответ на: комментарий от Gramozeka

Мне интересен опыт живых, реальных кодеров

Живые кодеры юзают библиотечные функции и не занимаются настолько великами. Кто в здравом уме при живой библиотечной функции будет её переизобретать. Переизобретают, например, всякие пхп/жс фреймворки, магазинные, форумные движки и цмс.

crutch_master ★★★★★
()
Ответ на: комментарий от SkyMaverick

На микроконтроллерах элементарно реализуется табличная тригонометрия. Все очень просто: нам нужны значения синуса лишь от нуля до 90°; косинус по ним вычисляется элементарно. Тангенс можно вычислить как отношение синуса к косинусу (но если нужен тангенс с точностью повыше, придется его тоже табулировать).

Чтобы вычислить табличку, просто разбиваешь интервал 0..π/2 на неравномерные интервалы (где кусочно-линейная аппроксимация будет выбиваться за заданную наперед точность). Далее все просто: если тебе нужно вычислить sinα, ты бисекцией из таблички углов ищешь, в каком интервале находится твоя α. Потом берешь из этой таблички α₀, sinα₀ и коэффициент наклона — и элементарно вычисляешь sinα с заданной точностью.

anonymous
()
Ответ на: комментарий от SkyMaverick

Ну, допустим, есть задача обеспечить сборку и без -lm.

Так это не соответствует условию «при живой библиотеке».

crutch_master ★★★★★
()
Ответ на: комментарий от crutch_master

Кстати, ряд Маклорена быстро сходится для cos/sin. Не больше 14 слагаемых всего нужно посчитать для точности 1e-7.

function no_standard_cos(x: double): double;
const
  eps:double = 1e-7;
var
  t, n: double;
  i: int32;
begin
  x := x - trunc(x / (2*pi))*2*pi;
  result := 1;
  t := 1;
  n := 1;
  i := 0;
  repeat
    t := -t * sqr(x)/(n*(n+1));
    result := result + t;
    n := n + 2;
    inc(i);
  until abs(t) < eps;
  writeln(UTF8ToConsole('Количество итераций для вычисления cos = '), i);
end;

https://imgur.com/a/40Fzds3

fsb4000 ★★★★★
()
Ответ на: комментарий от Harald

можно выдрать нужные куски из libm

да чего уж там, хлящщи с плеча! Всю глибсу «as is» затащить, да и дело в шляпе(в плохом смысле)).

Если просто копипастить код из системных библиотек, мы получим поколение имбецилов(с подвёрнутыми джинсами и без носков, но в кружевных стрингах поверх этих джинсов) с апломбом царствующего семейства и мозгами птеродактиля... кстати есть уже печальный пример такого стада - проект варгейминг, картинки то они красивые рисуют, а вот букварь по элементарной алгебре для них манускрипт Войнича, даже при наличии целой винды с уже скомпилированными во всех возможных вариантах математических примитивов. Но зато деньги любят пуще матери родной...

Gramozeka ★★
() автор топика
Последнее исправление: Gramozeka (всего исправлений: 1)
Ответ на: комментарий от Gramozeka

Одно дело учить вычислительную математику и численные методы, другое дело практическое применение в условиях ограниченных сроков

Harald ★★★★★
()
Ответ на: комментарий от Harald

Одно дело учить вычислительную математику и численные методы, другое дело практическое применение в условиях ограниченных сроков

другими словами - зачем вообще учить что-то, если всё время в цейтноте надо что-то применять, будем имитировать бурную деятельность, пока кто-там за нас всё сделает.

Если ты выучил «вычислительную математику и численные методы», то «практическое применение в условиях ограниченных сроков» тебя никак не ущемляет, ну разве что скорость набора на клаве.

Gramozeka ★★
() автор топика
Ответ на: комментарий от fsb4000

будет один в один как в формуле

В какой формуле?
У ТСа ряд Тейлора:
1-(x**2/2!)+(x**4/4!)-(x**6/6!)+(x**8/8!)-...
sum( (-1 ** n) * ( x ** (2 *n) / (2*n)!) )
https://ru.wikipedia.org/wiki/Ряд_Тейлора

crutch_master ★★★★★
()
Последнее исправление: crutch_master (всего исправлений: 1)
Ответ на: комментарий от crutch_master

В какой формуле?

Раздели n-ое слагаемое ряда Маклорена на (n+1)-ое.

Вот и будет формула.

Зачем считать слагаемое заного полностью?

fsb4000 ★★★★★
()
Ответ на: комментарий от Gramozeka

Если ты выучил «вычислительную математику и численные методы», то «практическое применение в условиях ограниченных сроков» тебя никак не ущемляет, ну разве что скорость набора на клаве.

Я это всё в голове целиком всё равно не держу, а восстанавливать это всё займёт дольше, чем выдрать из libm. Ну за исключением крайних случаев, когда нужно вычислять синус быстрее, либо точнее, либо ещё какие-то условия, которым имеющаяся свободная реализация не удовлетворяет.

Harald ★★★★★
()
Ответ на: комментарий от Harald

быстрее, либо точнее, либо ещё какие-то условия, которым имеющаяся свободная реализация не удовлетворяет.

так об этом весь тред! Или ты по умолчанию считаешь, что раз я привёл пример написанного ногами на коленке кода(распевая песни «джимми-джимми, ача-ача», не приходя в сознание), то я не в курсе за готовые методы которые даёт система?

Gramozeka ★★
() автор топика
Ответ на: комментарий от fsb4000

Раздели n-ое слагаемое ряда Маклорена на (n+1)-ое.
Вот и будет формула.
Зачем считать слагаемое заного полностью?

Не спортивно. Так можно докатиться до гошного варианта с коэфициентами.

crutch_master ★★★★★
()
Ответ на: комментарий от crutch_master

Деда, чем тебе хипсторы-то не удодили с картохой?

да ничем, просто эталонный случай пейсателей ногами, любящих боливуд. Таких в зоопарках показывать надо под вывеской «вот до чего доводит злоупотребление смузями и вейпами»

Gramozeka ★★
() автор топика
Ответ на: комментарий от anonymous

eddy_em: Вот так

Может лучше ind = SZ * rad / _PI_2, чем твоя бисекция?

Отступы табами, кста, только дауничи делают.

anonymous
()
Ответ на: комментарий от unanimous

я вот все чаще вижу подобного рода форматирование кода, это мода такая позерская сейчас так оформлять, или попытка в индивидуальность? Кто был изначальным нулевым пациентом который начал этот маразм в форматировании?

anonymous
()
Ответ на: комментарий от fsb4000

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

anonymous
()
Ответ на: комментарий от anonymous

Код написан много лет назад, болван, я понятия не имею, где ты своих снобистских комплексов набрался.

P.S. По timestamp – в ноябре 2010.

unanimous ★★★★★
()
Последнее исправление: unanimous (всего исправлений: 1)
Ответ на: комментарий от anonymous

Ты не обратил внимания на то, что сетка по аргументу неравномерная? Иначе не получилось бы оптимизировать количество узлов!

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.