Skip to content

Commit 4a0c073

Browse files
kaydotdevsiriak
andauthored
Maclaurin series approximation (#149)
* Prepare infrastructure * Basic nonlinear functions implementation in order form * Exp & Cos & Sin test cases * Exp function approximation in error form * Error form series for trigonometry functions * Update README.md Co-authored-by: Andrii Siriak <siryaka@gmail.com>
1 parent 95ab2a7 commit 4a0c073

File tree

3 files changed

+275
-1
lines changed

3 files changed

+275
-1
lines changed
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
using System;
2+
using Algorithms.Numeric.Series;
3+
using NUnit.Framework;
4+
5+
6+
namespace Algorithms.Tests.Numeric.Decomposition
7+
{
8+
public class MaclaurinTests
9+
{
10+
[TestCase(0.01, 3, 0.01)]
11+
[TestCase(1, 7, 0.001)]
12+
[TestCase(-1.2, 7, 0.001)]
13+
public void Exp_TermsForm_ValidCases(double point, int terms, double expectedError)
14+
{
15+
// Arrange
16+
var expected = Math.Exp(point);
17+
18+
// Act
19+
var actual = Maclaurin.Exp(point, terms);
20+
21+
// Assert
22+
Assert.IsTrue(Math.Abs(expected - actual) < expectedError);
23+
}
24+
25+
[Test]
26+
public void Exp_TermsForm_InvalidCase() =>
27+
Assert.Throws<ArgumentOutOfRangeException>(() => Maclaurin.Exp(0, -1));
28+
29+
[TestCase(0, 1, 0.001)]
30+
[TestCase(1, 7, 0.001)]
31+
[TestCase(1.57, 7, 0.001)]
32+
[TestCase(3.14, 7, 0.001)]
33+
public void Sin_TermsForm_ValidCases(double point, int terms, double expectedError)
34+
{
35+
// Arrange
36+
var expected = Math.Sin(point);
37+
38+
// Act
39+
var actual = Maclaurin.Sin(point, terms);
40+
41+
// Assert
42+
Assert.IsTrue(Math.Abs(expected - actual) < expectedError);
43+
}
44+
45+
[Test]
46+
public void Sin_TermsForm_InvalidCase() =>
47+
Assert.Throws<ArgumentOutOfRangeException>(() => Maclaurin.Sin(0, -1));
48+
49+
[TestCase(0, 1, 0.001)]
50+
[TestCase(1, 7, 0.001)]
51+
[TestCase(1.57, 7, 0.001)]
52+
[TestCase(3.14, 7, 0.001)]
53+
public void Cos_TermsForm_ValidCases(double point, int terms, double expectedError)
54+
{
55+
// Arrange
56+
var expected = Math.Cos(point);
57+
58+
// Act
59+
var actual = Maclaurin.Cos(point, terms);
60+
61+
// Assert
62+
Assert.IsTrue(Math.Abs(expected - actual) < expectedError);
63+
}
64+
65+
[Test]
66+
public void Cos_TermsForm_InvalidCase() =>
67+
Assert.Throws<ArgumentOutOfRangeException>(() => Maclaurin.Cos(0, -1));
68+
69+
[TestCase(0.1, 0.001)]
70+
[TestCase(0.1, 0.00001)]
71+
[TestCase(2.1, 0.001)]
72+
[TestCase(-1.2, 0.001)]
73+
public void Exp_ErrorForm_ValidCases(double point, double error)
74+
{
75+
// Arrange
76+
var expected = Math.Exp(point);
77+
78+
// Act
79+
var actual = Maclaurin.Exp(point, error);
80+
81+
// Assert
82+
Assert.IsTrue(Math.Abs(expected - actual) < error);
83+
}
84+
85+
[TestCase(0.0)]
86+
[TestCase(1.0)]
87+
public void Exp_ErrorForm_InvalidCases(double error) =>
88+
Assert.Throws<ArgumentException>(() => Maclaurin.Exp(0.0, error));
89+
90+
[TestCase(0, 0.001)]
91+
[TestCase(1, 0.00001)]
92+
[TestCase(1.57, 0.0001)]
93+
[TestCase(3.14, 0.0001)]
94+
public void Sin_ErrorForm_ValidCases(double point, double error)
95+
{
96+
// Arrange
97+
var expected = Math.Sin(point);
98+
99+
// Act
100+
var actual = Maclaurin.Sin(point, error);
101+
102+
// Assert
103+
Assert.IsTrue(Math.Abs(expected - actual) < error);
104+
}
105+
106+
[TestCase(0.0)]
107+
[TestCase(1.0)]
108+
public void Sin_ErrorForm_InvalidCases(double error) =>
109+
Assert.Throws<ArgumentException>(() => Maclaurin.Sin(0.0, error));
110+
111+
[TestCase(0, 0.001)]
112+
[TestCase(1, 0.00001)]
113+
[TestCase(1.57, 0.0001)]
114+
[TestCase(3.14, 0.0001)]
115+
public void Cos_ErrorForm_ValidCases(double point, double error)
116+
{
117+
// Arrange
118+
var expected = Math.Cos(point);
119+
120+
// Act
121+
var actual = Maclaurin.Cos(point, error);
122+
123+
// Assert
124+
Assert.IsTrue(Math.Abs(expected - actual) < error);
125+
}
126+
127+
[TestCase(0.0)]
128+
[TestCase(1.0)]
129+
public void Cos_ErrorForm_InvalidCases(double error) =>
130+
Assert.Throws<ArgumentException>(() => Maclaurin.Cos(0.0, error));
131+
}
132+
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
using System;
2+
using System.Linq;
3+
4+
namespace Algorithms.Numeric.Series
5+
{
6+
/// <summary>
7+
/// Maclaurin series calculates nonlinear functions approximation
8+
/// starting from point x = 0 in a form of infinite power series:
9+
/// f(x) = f(0) + f'(0) * x + ... + (f'n(0) * (x ^ n)) / n! + ...,
10+
/// where n is natural number.
11+
/// </summary>
12+
public static class Maclaurin
13+
{
14+
/// <summary>
15+
/// Calculates approximation of e^x function:
16+
/// e^x = 1 + x + x^2 / 2! + ... + x^n / n! + ...,
17+
/// where n is number of terms (natural number),
18+
/// and x is given point (rational number).
19+
/// </summary>
20+
/// <param name="x">Given point.</param>
21+
/// <param name="n">The number of terms in polynomial.</param>
22+
/// <returns>Approximated value of the function in the given point.</returns>
23+
public static double Exp(double x, int n) =>
24+
Enumerable.Range(0, n).Sum(i => ExpTerm(x, i));
25+
26+
/// <summary>
27+
/// Calculates approximation of sin(x) function:
28+
/// sin(x) = x - x^3 / 3! + ... + (-1)^n * x^(2*n + 1) / (2*n + 1)! + ...,
29+
/// where n is number of terms (natural number),
30+
/// and x is given point (rational number).
31+
/// </summary>
32+
/// <param name="x">Given point.</param>
33+
/// <param name="n">The number of terms in polynomial.</param>
34+
/// <returns>Approximated value of the function in the given point.</returns>
35+
public static double Sin(double x, int n) =>
36+
Enumerable.Range(0, n).Sum(i => SinTerm(x, i));
37+
38+
/// <summary>
39+
/// Calculates approximation of cos(x) function:
40+
/// cos(x) = 1 - x^2 / 2! + ... + (-1)^n * x^(2*n) / (2*n)! + ...,
41+
/// where n is number of terms (natural number),
42+
/// and x is given point (rational number).
43+
/// </summary>
44+
/// <param name="x">Given point.</param>
45+
/// <param name="n">The number of terms in polynomial.</param>
46+
/// <returns>Approximated value of the function in the given point.</returns>
47+
public static double Cos(double x, int n) =>
48+
Enumerable.Range(0, n).Sum(i => CosTerm(x, i));
49+
50+
/// <summary>
51+
/// Calculates approximation of e^x function:
52+
/// e^x = 1 + x + x^2 / 2! + ... + x^n / n! + ...,
53+
/// and x is given point (rational number).
54+
/// </summary>
55+
/// <param name="x">Given point.</param>
56+
/// <param name="error">Last term error value.</param>
57+
/// <returns>Approximated value of the function in the given point.</returns>
58+
/// <exception cref="ArgumentException">Error value is not on interval (0.0; 1.0).</exception>
59+
public static double Exp(double x, double error = 0.00001) => ErrorTermWrapper(x, error, ExpTerm);
60+
61+
/// <summary>
62+
/// Calculates approximation of sin(x) function:
63+
/// sin(x) = x - x^3 / 3! + ... + (-1)^n * x^(2*n + 1) / (2*n + 1)! + ...,
64+
/// and x is given point (rational number).
65+
/// </summary>
66+
/// <param name="x">Given point.</param>
67+
/// <param name="error">Last term error value.</param>
68+
/// <returns>Approximated value of the function in the given point.</returns>
69+
/// <exception cref="ArgumentException">Error value is not on interval (0.0; 1.0).</exception>
70+
public static double Sin(double x, double error = 0.00001) => ErrorTermWrapper(x, error, SinTerm);
71+
72+
/// <summary>
73+
/// Calculates approximation of cos(x) function:
74+
/// cos(x) = 1 - x^2 / 2! + ... + (-1)^n * x^(2*n) / (2*n)! + ...,
75+
/// and x is given point (rational number).
76+
/// </summary>
77+
/// <param name="x">Given point.</param>
78+
/// <param name="error">Last term error value.</param>
79+
/// <returns>Approximated value of the function in the given point.</returns>
80+
/// <exception cref="ArgumentException">Error value is not on interval (0.0; 1.0).</exception>
81+
public static double Cos(double x, double error = 0.00001) => ErrorTermWrapper(x, error, CosTerm);
82+
83+
/// <summary>
84+
/// Wrapper function for calculating approximation with estimated
85+
/// count of terms, where last term value is less than given error.
86+
/// </summary>
87+
/// <param name="x">Given point.</param>
88+
/// <param name="error">Last term error value.</param>
89+
/// <param name="term">Indexed term of approximation series.</param>
90+
/// <returns>Approximated value of the function in the given point.</returns>
91+
/// <exception cref="ArgumentException">Error value is not on interval (0.0; 1.0).</exception>
92+
private static double ErrorTermWrapper(double x, double error, Func<double, int, double> term)
93+
{
94+
if (error <= 0.0 || error >= 1.0)
95+
{
96+
throw new ArgumentException("Error value is not on interval (0.0; 1.0).");
97+
}
98+
99+
var i = 0;
100+
var termCoefficient = 0.0;
101+
var result = 0.0;
102+
103+
do
104+
{
105+
result += termCoefficient;
106+
termCoefficient = term(x, i);
107+
i++;
108+
}
109+
while (Math.Abs(termCoefficient) > error);
110+
111+
return result;
112+
}
113+
114+
/// <summary>
115+
/// Single term for e^x function approximation: x^i / i!.
116+
/// </summary>
117+
/// <param name="x">Given point.</param>
118+
/// <param name="i">Term index from 0 to n.</param>
119+
/// <returns>Single term value.</returns>
120+
private static double ExpTerm(double x, int i) => Math.Pow(x, i) / Factorial.Calculate(i);
121+
122+
/// <summary>
123+
/// Single term for sin(x) function approximation: (-1)^i * x^(2*i + 1) / (2*i + 1)!.
124+
/// </summary>
125+
/// <param name="x">Given point.</param>
126+
/// <param name="i">Term index from 0 to n.</param>
127+
/// <returns>Single term value.</returns>
128+
private static double SinTerm(double x, int i) =>
129+
(Math.Pow(-1, i) / Factorial.Calculate(2 * i + 1)) * Math.Pow(x, 2 * i + 1);
130+
131+
/// <summary>
132+
/// Single term for cos(x) function approximation: (-1)^i * x^(2*i) / (2*i)!.
133+
/// </summary>
134+
/// <param name="x">Given point.</param>
135+
/// <param name="i">Term index from 0 to n.</param>
136+
/// <returns>Single term value.</returns>
137+
private static double CosTerm(double x, int i) =>
138+
(Math.Pow(-1, i) / Factorial.Calculate(2 * i)) * Math.Pow(x, 2 * i);
139+
}
140+
}

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ This repository contains algorithms and data structures implemented in C# for ed
2727
* [Euclidean GCD](./Algorithms/Numeric/GreatestCommonDivisor/EuclideanGreatestCommonDivisorFinder.cs)
2828
* [Binary GCD](./Algorithms/Numeric/GreatestCommonDivisor/BinaryGreatestCommonDivisorFinder.cs)
2929
* [Factorization](./Algorithms/Numeric/Factorization)
30-
* [Trial division](./Algorithms/Numeric/Factorization/TrialDivisionFactorizer.cs)
30+
* [Trial division](./Algorithms/Numeric/Factorization/TrialDivisionFactorizer.cs)
31+
* [Series](./Algorithms/Numeric/Series/)
32+
* [Maclaurin](./Algorithms/Numeric/Series/Maclaurin.cs)
3133
* [Gauss-Jordan Elimination](./Algorithms/Numeric/GaussJordanElimination.cs)
3234
* [Searches](./Algorithms/Search/)
3335
* [A-Star](./Algorithms/Search/AStar/)

0 commit comments

Comments
 (0)