Chebyshev coefficients: Difference between revisions

Rename Perl 6 -> Raku, alphabetize, minor clean-up
m (→‎{{header|REXX}}: changed whitespace, changed a variable name.)
(Rename Perl 6 -> Raku, alphabetize, minor clean-up)
Line 2:
<p>Chebyshev coefficients are the basis of polynomial approximations of functions. Write a program to generate Chebyshev coefficients.</p>
<p>Calculate coefficients: cosine function, 10 coefficients, interval 0 1</p>
 
=={{header|C}}==
C99.
Line 72 ⟶ 73:
}</lang>
 
=={{header|C++ sharp|C#}}==
Based on the C99 implementation above. The main improvement is that, because C++ containers handle memory for us, we can use a more functional style.
 
The two overloads of cheb_coef show a useful idiom for working with C++ templates; the non-template code, which does all the mathematical work, can be placed in a source file so that it is compiled only once (reducing code bloat from repeating substantial blocks of code). The template function is a minimal wrapper to call the non-template implementation.
 
The wrapper class ChebyshevApprox_ supports very terse user code.
 
<lang CPP>
#include <iostream>
#include <iomanip>
#include <string>
#include <cmath>
#include <utility>
#include <vector>
 
using namespace std;
 
static const double PI = acos(-1.0);
 
double affine_remap(const pair<double, double>& from, double x, const pair<double, double>& to)
{
return to.first + (x - from.first) * (to.second - to.first) / (from.second - from.first);
}
 
vector<double> cheb_coef(const vector<double>& f_vals)
{
const int n = f_vals.size();
const double theta = PI / n;
vector<double> retval(n, 0.0);
for (int ii = 0; ii < n; ++ii)
{
double f = f_vals[ii] * 2.0 / n;
const double phi = (ii + 0.5) * theta;
double c1 = cos(phi), s1 = sin(phi);
double c = 1.0, s = 0.0;
for (int j = 0; j < n; j++)
{
retval[j] += f * c;
// update c -> cos(j*phi) for next value of j
const double cNext = c * c1 - s * s1;
s = c * s1 + s * c1;
c = cNext;
}
}
return retval;
}
 
template<class F_> vector<double> cheb_coef(const F_& func, int n, const pair<double, double>& domain)
{
auto remap = [&](double x){return affine_remap({ -1.0, 1.0 }, x, domain); };
const double theta = PI / n;
vector<double> fVals(n);
for (int ii = 0; ii < n; ++ii)
fVals[ii] = func(remap(cos((ii + 0.5) * theta)));
return cheb_coef(fVals);
}
 
double cheb_eval(const vector<double>& coef, double x)
{
double a = 1.0, b = x, c;
double retval = 0.5 * coef[0] + b * coef[1];
for (auto pc = coef.begin() + 2; pc != coef.end(); a = b, b = c, ++pc)
{
c = 2.0 * b * x - a;
retval += (*pc) * c;
}
return retval;
}
double cheb_eval(const vector<double>& coef, const pair<double, double>& domain, double x)
{
return cheb_eval(coef, affine_remap(domain, x, { -1.0, 1.0 }));
}
 
struct ChebyshevApprox_
{
vector<double> coeffs_;
pair<double, double> domain_;
 
double operator()(double x) const { return cheb_eval(coeffs_, domain_, x); }
 
template<class F_> ChebyshevApprox_
(const F_& func,
int n,
const pair<double, double>& domain)
:
coeffs_(cheb_coef(func, n, domain)),
domain_(domain)
{ }
};
 
 
int main(void)
{
static const int N = 10;
ChebyshevApprox_ fApprox(cos, N, { 0.0, 1.0 });
cout << "Coefficients: " << setprecision(14);
for (const auto& c : fApprox.coeffs_)
cout << "\t" << c << "\n";
 
for (;;)
{
cout << "Enter x, or non-numeric value to quit:\n";
double x;
if (!(cin >> x))
return 0;
cout << "True value: \t" << cos(x) << "\n";
cout << "Approximate: \t" << fApprox(x) << "\n";
}
}
</lang>
 
=={{header|C#|C sharp}}==
{{trans|C++}}
<lang csharp>using System;
Line 329 ⟶ 219:
0.900 0.62160996827066 0.62160996827111 4.444223E-013
0.950 0.58168308946388 0.58168308946379 -8.992806E-014</pre>
 
=={{header|C++}}==
Based on the C99 implementation above. The main improvement is that, because C++ containers handle memory for us, we can use a more functional style.
 
The two overloads of cheb_coef show a useful idiom for working with C++ templates; the non-template code, which does all the mathematical work, can be placed in a source file so that it is compiled only once (reducing code bloat from repeating substantial blocks of code). The template function is a minimal wrapper to call the non-template implementation.
 
The wrapper class ChebyshevApprox_ supports very terse user code.
 
<lang CPP>
#include <iostream>
#include <iomanip>
#include <string>
#include <cmath>
#include <utility>
#include <vector>
 
using namespace std;
 
static const double PI = acos(-1.0);
 
double affine_remap(const pair<double, double>& from, double x, const pair<double, double>& to)
{
return to.first + (x - from.first) * (to.second - to.first) / (from.second - from.first);
}
 
vector<double> cheb_coef(const vector<double>& f_vals)
{
const int n = f_vals.size();
const double theta = PI / n;
vector<double> retval(n, 0.0);
for (int ii = 0; ii < n; ++ii)
{
double f = f_vals[ii] * 2.0 / n;
const double phi = (ii + 0.5) * theta;
double c1 = cos(phi), s1 = sin(phi);
double c = 1.0, s = 0.0;
for (int j = 0; j < n; j++)
{
retval[j] += f * c;
// update c -> cos(j*phi) for next value of j
const double cNext = c * c1 - s * s1;
s = c * s1 + s * c1;
c = cNext;
}
}
return retval;
}
 
template<class F_> vector<double> cheb_coef(const F_& func, int n, const pair<double, double>& domain)
{
auto remap = [&](double x){return affine_remap({ -1.0, 1.0 }, x, domain); };
const double theta = PI / n;
vector<double> fVals(n);
for (int ii = 0; ii < n; ++ii)
fVals[ii] = func(remap(cos((ii + 0.5) * theta)));
return cheb_coef(fVals);
}
 
double cheb_eval(const vector<double>& coef, double x)
{
double a = 1.0, b = x, c;
double retval = 0.5 * coef[0] + b * coef[1];
for (auto pc = coef.begin() + 2; pc != coef.end(); a = b, b = c, ++pc)
{
c = 2.0 * b * x - a;
retval += (*pc) * c;
}
return retval;
}
double cheb_eval(const vector<double>& coef, const pair<double, double>& domain, double x)
{
return cheb_eval(coef, affine_remap(domain, x, { -1.0, 1.0 }));
}
 
struct ChebyshevApprox_
{
vector<double> coeffs_;
pair<double, double> domain_;
 
double operator()(double x) const { return cheb_eval(coeffs_, domain_, x); }
 
template<class F_> ChebyshevApprox_
(const F_& func,
int n,
const pair<double, double>& domain)
:
coeffs_(cheb_coef(func, n, domain)),
domain_(domain)
{ }
};
 
 
int main(void)
{
static const int N = 10;
ChebyshevApprox_ fApprox(cos, N, { 0.0, 1.0 });
cout << "Coefficients: " << setprecision(14);
for (const auto& c : fApprox.coeffs_)
cout << "\t" << c << "\n";
 
for (;;)
{
cout << "Enter x, or non-numeric value to quit:\n";
double x;
if (!(cin >> x))
return 0;
cout << "True value: \t" << cos(x) << "\n";
cout << "Approximate: \t" << fApprox(x) << "\n";
}
}
</lang>
 
=={{header|D}}==
Line 846 ⟶ 847:
9 : -0,0000000000100189955816952521
</pre>
 
 
=={{header|Perl}}==
Line 880:
6.59629917354465e-10
-1.00219943455215e-11</pre>
 
=={{header|Perl 6}}==
{{works with|Rakudo|2015.12}}
{{trans|C}}
 
<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>
 
{{out}}
<pre>
+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
</pre>
 
=={{header|Phix}}==
Line 1,117 ⟶ 1,085:
6.596299173544651e-010
-1.0022016549982027e-011)</pre>
 
=={{header|Raku}}==
(formerly Perl 6)
{{works with|Rakudo|2015.12}}
{{trans|C}}
 
<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>
 
{{out}}
<pre>
+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
</pre>
 
=={{header|REXX}}==
10,327

edits