Chebyshev coefficients
Chebyshev coefficients are the basis of polynomial approximations of functions. Write a program to generate Chebyshev coefficients.
Calculate coefficients: cosine function, 10 coefficients, interval 0 1
C
<lang C>// Program to calculate Chebyshev coefficients // Code taken from Numerical Recipes in C 1/e
- include <math.h>
- define PI 3.141592653589793
void chebft(float a, float b, float c[], int n, float (*func)(float)) {
int k,j; float fac,bpa,bma,f[300]; bma = 0.5 * (b-a); bpa = 0.5 * (b+a); for(k = 0;k<n;k++) { float y = cos(PI*(k+0.5)/n); f[k] = (*func)(y*bma+bpa); } fac = 2.0/n; for (j = 0;j<n;j++) { double sum = 0.0; for(k = 0;k<n;k++) sum += f[k] * cos(PI*j*(k+0.5)/n); c[j] = fac*sum; }
}</lang>
J
From 'J for C Programmers: Calculating Chebyshev Coefficients [[1]] <lang J> chebft =: adverb define
f =. u 0.5 * (+/y) - (-/y) * 2 o. o. (0.5 + i. x) % x
(2 % x) * +/ f * 2 o. o. (0.5 + i. x) *"0 1 (i. x) % x
) </lang> Calculate coefficients: <lang J>
10 (2&o.) chebft 0 1
1.64717 _0.232299 _0.0537151 0.00245824 0.000282119 _7.72223e_6 _5.89856e_7 1.15214e_8 6.59629e_10 _1.00227e_11 </lang>
Perl
<lang perl>use constant PI => 3.141592653589793;
sub chebft {
my($func, $a, $b, $n) = @_; my($bma, $bpa) = ( 0.5*($b-$a), 0.5*($b+$a) );
my @pin = map { ($_ + 0.5) * (PI/$n) } 0..$n-1; my @f = map { $func->( cos($_) * $bma + $bpa ) } @pin; my @c = 0 x $n; for my $j (0 .. $n-1) { $c[$j] += $f[$_] * cos($j * $pin[$_]) for 0..$n-1; $c[$j] *= (2.0/$n); } @c;
}
print "$_\n" for chebft(sub{cos($_[0])}, 0, 1, 10);</lang>
- Output:
1.64716947539031 -0.232299371615172 -0.0537151146220477 0.00245823526698163 0.000282119057433938 -7.72222915566001e-06 -5.89855645105608e-07 1.15214274787334e-08 6.59629917354465e-10 -1.00219943455215e-11
Perl 6
<lang perl6>sub chebft ( Code $func, Real $a, Real $b, Int $n ) {
my $bma = 0.5 * ( $b - $a ); my $bpa = 0.5 * ( $b + $a );
my @pi_n = ( (^$n).list »+» 0.5 ) »*» ( pi / $n ); my @f = ( @pi_n».cos »*» $bma »+» $bpa )».$func; my @sums = map { [+] @f »*« ( @pi_n »*» $_ )».cos }, ^$n;
return @sums »*» ( 2 / $n );
}
say .fmt('%+13.7e') for chebft &cos, 0, 1, 10;</lang>
- Output:
+1.6471695e+00 -2.3229937e-01 -5.3715115e-02 +2.4582353e-03 +2.8211906e-04 -7.7222292e-06 -5.8985565e-07 +1.1521427e-08 +6.5962992e-10 -1.0021994e-11
Racket
<lang racket>#lang typed/racket (: chebft (Real Real Nonnegative-Integer (Real -> Real) -> (Vectorof Real))) (define (chebft a b n func)
(define b-a/2 (/ (- b a) 2)) (define b+a/2 (/ (+ b a) 2)) (define pi/n (/ pi n)) (define fac (/ 2 n))
(define f (for/vector : (Vectorof Real) ((k : Nonnegative-Integer (in-range n))) (define y (cos (* pi/n (+ k 1/2)))) (func (+ (* y b-a/2) b+a/2))))
(for/vector : (Vectorof Real) ((j : Nonnegative-Integer (in-range n))) (define s (for/sum : Real ((k : Nonnegative-Integer (in-range n))) (* (vector-ref f k) (cos (* pi/n j (+ k 1/2)))))) (* fac s)))
(module+ test
(chebft 0 1 10 cos))
- Tim Brown 2015</lang>
- Output:
'#(1.6471694753903137 -0.2322993716151719 -0.05371511462204768 0.0024582352669816343 0.0002821190574339161 -7.722229155637806e-006 -5.898556451056081e-007 1.1521427500937876e-008 6.596299173544651e-010 -1.0022016549982027e-011)
REXX
The following REXX program is a translation of the C program plus added optimizations. <lang rexx>/*REXX program calculates ten Chebyshev coefficients for the range 0 ──► 1.*/ /*Pafnuty Lvovich Chebysheff: Chebysheff [English transliteration] */ /*─────────────────────────── Chebyshov [ " " ] */ /*─────────────────────────── Tchebychev [French " ] */ /*─────────────────────────── Tchebysheff [ " " ] */ /*─────────────────────────── Tschebyschow [German " ] */ /*─────────────────────────── Tschebyschev [ " " ] */ /*─────────────────────────── Tschebyschef [ " " ] */ /*─────────────────────────── Tschebyscheff [ " " ] */ numeric digits length(pi()) /*DIGITS default is nine, but use 63. */ parse arg a b n . /*obtain optional arguments from the CL*/ if a== | a==',' then a=0 /*A not specified? Then use default.*/ if b== | b==',' then b=1 /*B " " " " " */ if n== | n==',' then n=10 /*N " " " " " */ bma =(b-a)/2 /*calculate one─half of the difference.*/ bpa =(b+a)/2 /* " " " " sum. */ pi@n=pi/n /*calculate a handy─dandy value. */
do k=0 for n f.k=cos(cos(pi@n * (k+.5)) * bma + bpa) end /*k*/
fac=2/n /*calculate another handy─dandy value. */
do j=0 for n; $=0 z=pi@n * j do m=0 for n $=$ + f.m * cos(z * (m+.5)) end /*m*/ cheby.j=fac*$ /*uses 63 digs, but only shows 30 ►───┐*/ say right(j,length(n)+3) ' Chebyshev coefficient is:', /*│*/ left(,cheby.j>=0) format(cheby.j,,30) /* ◄───────────┘*/ end /*j*/
exit /*stick a fork in it, we're all done. */ /*────────────────────────────────────────────────────────────────────────────*/ cos: procedure; parse arg x; numeric digits digits()+10; numeric fuzz 5
z=1; _=1; x=r2r(x); a=abs(x); q=x*x if a=pi then return -1; if a=pi*.5 | a=pi*2 then return 0; pi3=pi/3 if a=pi3 then return .5; if a=2*pi3 then return -.5 do ?=2 by 2 until p=z; p=z; _=-_*q/(?*(?-1)); z=z+_; end /*?*/ return z
/*────────────────────────────────────────────────────────────────────────────*/ pi: pi=3.1415926535897932384626433832795028841971693993751058209749446;return pi /*────────────────────────────────────────────────────────────────────────────*/ r2r: return arg(1) // (pi()*2) /*normalize radians ───► a unit circle.*/</lang> output when using the default inputs:
0 Chebyshev coefficient is: 1.647169475390313686961473816798 1 Chebyshev coefficient is: -0.232299371615171942121038341178 2 Chebyshev coefficient is: -0.053715114622047555071596203933 3 Chebyshev coefficient is: 0.002458235266981479866768882753 4 Chebyshev coefficient is: 0.000282119057434005702410217295 5 Chebyshev coefficient is: -0.000007722229155810577892832847 6 Chebyshev coefficient is: -5.898556452177103343296676960522E-7 7 Chebyshev coefficient is: 1.152142733310315857327524390711E-8 8 Chebyshev coefficient is: 6.596300035120132380676859918562E-10 9 Chebyshev coefficient is: -1.002259170944625675156620531665E-11
zkl
<lang zkl>var [const] PI=(1.0).pi; fcn chebft(a,b,n,func){
bma,bpa,fac := 0.5*(b - a), 0.5*(b + a), 2.0/n; f:=n.pump(List,'wrap(k){ (PI*(0.5 + k)/n).cos():func(_*bma + bpa) }); n.pump(List,'wrap(j){ fac*n.reduce('wrap(sum,k){ sum + f[k]*(PI*j*(0.5 + k)/n).cos() },0.0); })
} chebft(0.0,1.0,10,fcn(x){ x.cos() }).enumerate().concat("\n").println();</lang>
- Output:
L(0,1.64717) L(1,-0.232299) L(2,-0.0537151) L(3,0.00245824) L(4,0.000282119) L(5,-7.72223e-06) L(6,-5.89856e-07) L(7,1.15214e-08) L(8,6.5963e-10) L(9,-1.00219e-11)