
Сообщение от
kondor3000
Выкладываю новые функции на ST, версия OWEN Logic2.6.345
Sin_Cos_Tg_CTg_ArcSin_ArcCos_ArcTg (x)
Не слишком удачные реализации.
Более рациональный подход - итерационные вычисления слагаемого на основе предыдущего значения.
Была нужна только функция sin(x), её и реализовывал. Другие функции - подождут своего часа.
Смысл алгоритма - сначала инициализация переменных, потом итерационно вычисляется очередное слагаемое на основе предыдущего его значения
У sin
слагаемое на предыдущей итерации А(i-1) равно
A(i-1) := (-1)^(i-1) * x^(2i-1) / (2i-1)!
а слагаемое на нынешней итерации А(i) равно
A(i) := (-1)^(i) * x^(2i+1) / (2i+1)!
Разделю А(i) на А(i-1) и получу множитель для перехода от A(i-1) к A(i)
A(i) := m * A(i-1)
m := A(i) / A(i-1)
= [(-1)^(i) * x^(2i+1) / (2i+1)!] / [(-1)^(i-1) * x^(2i-1) / (2i-1)!]
= (-1)^1 * x^2 / [(2i+1)*(2i)]
= -x^2 / [(2i+1)*(2i)]
Дальше просто реализую на языке программирования
Попутно, перед вычислениями привожу аргумент периодической функции к меньшему диапазону.
Чтобы не испытывать судьбу, непредсказуемый цикл REPEAT ограничиваю число итераций количеством 10.
Число итераций 10 взял из соображений оценки 10-го слагаемого в сумме - напомню, что в самом начале аргумент приведён к узкому диапазону, что позволяет выполнить оценку погрешности в наихудшем случае. Сейчас уже не вспомню это значение, пересчитывать лень, но тогда решил, что приемлемой точности добьюсь.
Код:
function sin: real;
var_input
x : real;
end_var
var
n: udint;
Pi : real := 3.1415926535897932384626433832795;
Pi_2: real := 6.2831853071795864769252867665590;
a, s, xx: real;
f: udint;
end_var
// приведение аргумента к диапазону 0...2*Pi
if x < 0 then
n := real_to_udint(abs(x) / Pi_2) + 1;
x := x + udint_to_real(n) * Pi_2;
end_if;
if x > Pi_2 then
n := real_to_udint(abs(x) / Pi_2);
x := x - udint_to_real(n) * Pi_2;
end_if
f := 1;
a := x;
s := x;
xx := x*x;
repeat
a := - a * xx / udint_to_real(f+1) / udint_to_real(f+2);
f := f + 2;
s := s + a;
if f > 20 then
exit;
end_if;
until abs(a) < 0.0000001
end_repeat
sin := s;
end_function
Думаю, что можно улучшить, объявив переменную f типом real, т.к. значения небольшие и потери точности при сложении с 2 не произойдёт.