@@ -41,27 +41,7 @@ struct Polynomial(F)
4141 +/
4242 @optmath typeof (F.init * X.init * 1f + F.init) opCall (X)(in X x) const
4343 {
44- import mir.internal.utility: Iota;
45- auto ret = cast (typeof (return ))0 ;
46- if (coefficients)
47- {
48- ptrdiff_t i = coefficients.length - 1 ;
49- assert (i >= 0 );
50- auto c = cast ()coefficients[i];
51- static foreach (d; Iota! derivative)
52- c *= i - d;
53- ret = cast (typeof (return )) c;
54- while (-- i >= cast (ptrdiff_t )derivative)
55- {
56- assert (i < coefficients.length);
57- c = cast ()coefficients[i];
58- static foreach (d; Iota! derivative)
59- c *= i - d;
60- ret *= x;
61- ret += c;
62- }
63- }
64- return ret;
44+ return x.poly! derivative(this .coefficients[]);
6545 }
6646 }
6747}
@@ -81,9 +61,9 @@ version (mir_test) @safe pure nothrow @nogc unittest
8161 auto a = rcarray! (const double )(3.0 , 4.5 , 1.9 , 2 );
8262 auto p = a.polynomial;
8363
84- alias f = (x) => 3.0 + 4.5 * x^^ 1 + 1.9 * x^^ 2 + 2 * x^^ 3 ;
85- alias df = (x) => 4.5 + 2 * 1.9 * x^^ 1 + 3 * 2 * x^^ 2 ;
86- alias d2f = (x) => 2 * 1.9 + 6 * 2 * x^^ 1 ;
64+ alias f = (x) => 3.0 + 4.5 * x^^ 1 + 1.9 * x^^ 2 + 2 * x^^ 3 ;
65+ alias df = (x) => 4.5 + 2 * 1.9 * x^^ 1 + 3 * 2 * x^^ 2 ;
66+ alias d2f = (x) => 2 * 1.9 + 6 * 2 * x^^ 1 ;
8767
8868 assert (p(3.3 ).approxEqual(f(3.3 )));
8969 assert (p(7.2 ).approxEqual(f(7.2 )));
@@ -94,3 +74,153 @@ version (mir_test) @safe pure nothrow @nogc unittest
9474 assert (p.opCall ! 2 (3.3 ).approxEqual(d2f(3.3 )));
9575 assert (p.opCall ! 2 (7.2 ).approxEqual(d2f(7.2 )));
9676}
77+
78+ /+ +
79+ Evaluate polynomial.
80+
81+ Coefficients assumed to be in the order a0 + a1 * x ^^ 1 + ... + aN * x ^^ N
82+
83+ Params:
84+ F = controls type of output
85+ derivative = order of derivatives (default = 0)
86+
87+ Returns:
88+ Value of the polynomial, evaluated at `x`
89+
90+ See_also:
91+ $(WEB en.wikipedia.org/wiki/Polynomial, Polynomial).
92+ +/
93+ template poly (uint derivative = 0 )
94+ {
95+ import std.traits : ForeachType;
96+ /+ +
97+ Params:
98+ x = value to evaluate
99+ coefficients = coefficients of polynomial
100+ +/
101+ @optmath typeof (F.init * X.init * 1f + F.init) poly(X, F)(in X x, scope const F[] coefficients... )
102+ {
103+ import mir.internal.utility: Iota;
104+ auto ret = cast (typeof (return ))0 ;
105+ if (coefficients.length > 0 )
106+ {
107+ ptrdiff_t i = coefficients.length - 1 ;
108+ assert (i >= 0 );
109+ auto c = cast ()coefficients[i];
110+ static foreach (d; Iota! derivative)
111+ c *= i - d;
112+ ret = cast (typeof (return )) c;
113+ while (-- i >= cast (ptrdiff_t )derivative)
114+ {
115+ assert (i < coefficients.length);
116+ c = cast ()coefficients[i];
117+ static foreach (d; Iota! derivative)
118+ c *= i - d;
119+ ret *= x;
120+ ret += c;
121+ }
122+ }
123+ return ret;
124+ }
125+ }
126+
127+ // /
128+ version (mir_test) @safe pure nothrow unittest
129+ {
130+ import mir.math.common: approxEqual;
131+
132+ double [] x = [3.0 , 4.5 , 1.9 , 2 ];
133+
134+ alias f = (x) => 3.0 + 4.5 * x^^ 1 + 1.9 * x^^ 2 + 2 * x^^ 3 ;
135+ alias df = (x) => 4.5 + 2 * 1.9 * x^^ 1 + 3 * 2 * x^^ 2 ;
136+ alias d2f = (x) => 2 * 1.9 + 6 * 2 * x^^ 1 ;
137+
138+ assert (poly(3.3 , x).approxEqual(f(3.3 )));
139+ assert (poly(7.2 , x).approxEqual(f(7.2 )));
140+
141+ assert (poly! 1 (3.3 , x).approxEqual(df(3.3 )));
142+ assert (poly! 1 (7.2 , x).approxEqual(df(7.2 )));
143+
144+ assert (poly! 2 (3.3 , x).approxEqual(d2f(3.3 )));
145+ assert (poly! 2 (7.2 , x).approxEqual(d2f(7.2 )));
146+ }
147+
148+ // static array test
149+ version (mir_test) @safe pure @nogc nothrow unittest
150+ {
151+ import mir.math.common: approxEqual;
152+
153+ double [4 ] x = [3.0 , 4.5 , 1.9 , 2 ];
154+
155+ alias f = (x) => 3.0 + 4.5 * x^^ 1 + 1.9 * x^^ 2 + 2 * x^^ 3 ;
156+ alias df = (x) => 4.5 + 2 * 1.9 * x^^ 1 + 3 * 2 * x^^ 2 ;
157+ alias d2f = (x) => 2 * 1.9 + 6 * 2 * x^^ 1 ;
158+
159+ assert (poly(3.3 , x).approxEqual(f(3.3 )));
160+ assert (poly(7.2 , x).approxEqual(f(7.2 )));
161+
162+ assert (poly! 1 (3.3 , x).approxEqual(df(3.3 )));
163+ assert (poly! 1 (7.2 , x).approxEqual(df(7.2 )));
164+
165+ assert (poly! 2 (3.3 , x).approxEqual(d2f(3.3 )));
166+ assert (poly! 2 (7.2 , x).approxEqual(d2f(7.2 )));
167+ }
168+
169+ // Check coefficient.length = 3
170+ version (mir_test) @safe pure nothrow unittest
171+ {
172+ import mir.math.common: approxEqual;
173+
174+ double [] x = [3.0 , 4.5 , 1.9 ];
175+
176+ alias f = (x) => 3.0 + 4.5 * x^^ 1 + 1.9 * x^^ 2 ;
177+ alias df = (x) => 4.5 + 2 * 1.9 * x^^ 1 ;
178+ alias d2f = (x) => 2 * 1.9 ;
179+
180+ assert (poly(3.3 , x).approxEqual(f(3.3 )));
181+ assert (poly(7.2 , x).approxEqual(f(7.2 )));
182+
183+ assert (poly! 1 (3.3 , x).approxEqual(df(3.3 )));
184+ assert (poly! 1 (7.2 , x).approxEqual(df(7.2 )));
185+
186+ assert (poly! 2 (3.3 , x).approxEqual(d2f(3.3 )));
187+ assert (poly! 2 (7.2 , x).approxEqual(d2f(7.2 )));
188+ }
189+
190+ // Check coefficient.length = 2
191+ version (mir_test) @safe pure nothrow unittest
192+ {
193+ import mir.math.common: approxEqual;
194+
195+ double [] x = [3.0 , 4.5 ];
196+
197+ alias f = (x) => 3.0 + 4.5 * x^^ 1 ;
198+ alias df = (x) => 4.5 ;
199+ alias d2f = (x) => 0.0 ;
200+
201+ assert (poly(3.3 , x).approxEqual(f(3.3 )));
202+ assert (poly(7.2 , x).approxEqual(f(7.2 )));
203+
204+ assert (poly! 1 (3.3 , x).approxEqual(df(3.3 )));
205+ assert (poly! 1 (7.2 , x).approxEqual(df(7.2 )));
206+
207+ assert (poly! 2 (3.3 , x).approxEqual(d2f(3.3 )));
208+ assert (poly! 2 (7.2 , x).approxEqual(d2f(7.2 )));
209+ }
210+
211+ // Check coefficient.length = 1
212+ version (mir_test) @safe pure nothrow unittest
213+ {
214+ import mir.math.common: approxEqual;
215+
216+ double [] x = [3.0 ];
217+
218+ alias f = (x) => 3.0 ;
219+ alias df = (x) => 0.0 ;
220+
221+ assert (poly(3.3 , x).approxEqual(f(3.3 )));
222+ assert (poly(7.2 , x).approxEqual(f(7.2 )));
223+
224+ assert (poly! 1 (3.3 , x).approxEqual(df(3.3 )));
225+ assert (poly! 1 (7.2 , x).approxEqual(df(7.2 )));
226+ }
0 commit comments