I have the following code above my main method and all my other functions:
typedef double (*FUNC)(double);
double integrate(FUNC f, double a, double b){
double sum = 0;
for(int i=a; i<=b; i++){
sum = sum + (f * .0001); //error occurs here, red squiggly line under "f"
}
return sum;
}
In the Microsoft Visual Studio C++ compiler, I get an error: Expression must have arithmetic or enum type. I pointed out where the error comes from above in a comment. Can someone explain to me why I have this error and how I can resolve this error?
I take it you are trying to integrate f(x) for values of x from a to b?
In which case your code is quite incorrect.
Your 0.0001 seems to indicate that you are actually trying to use 10000 steps, in which case you would use something along the lines of:
const int steps = 10000;
double x = a;
double delta = (b - a) / steps;
for(int i = 0; i < steps; i++, x += delta)
You would then calculate use a call f(x) to call the function pointer, and sum that up.
Try using this instead
sum = sum + f(.0001);
Multiplying a function pointer by a fraction would not go so well.
Related
#include<iostream>
#include<cmath>
using namespace std;
float san= 0.25 ; float var= 0.75;
int findFact(int n)//factorial
{
return n == 1 ? 1 : n * findFact(n - 1);
}
int findNcR(int n, int r)//combination nCr
{
return findFact(n) / (findFact(n - r) * findFact(r));
}
double prob(int s, int v){ //recursive function for probability
if(s>=5) return 1; if(v>=5) return 0;
double sum = 0;
int m = 5-s;
for( int i=0; i<=m; i++){
sum += prob(s+i,v+m-i)*findNcR(m,i)*pow(san,i)*pow(var,m-i);
}
return sum;
}
int main(){
cout<< prob(2,1);
}
In DEV C++, there is no output printed when I compile and run the above code. I think its because of large fractional values involved. Any idea how I can get the output?
Please check the logic you use in your double prob(int s, int v) method.
You are going to infinity recursive like
S=2 V=1
S=2 V=4
S=2 V=7
The base case for your recursion, s==5 or v==5 is never getting hit. As you call your function with s=2, every time the prob function is called it is setting m to 3, and so on the first iteration of the loop (when i==0) it calls prob with s=2 and v=v+3. As you start with v==1, it successively calls prob(2,1), prob(2,4), prob(2,7), etc... and never gets any further.
I don't know what probability distribution you are trying to code so I can't offer any specific advice on how to fix this.
I've been trying to write a function to approximate an the value of an integral using the Composite Simpson's Rule.
template <typename func_type>
double simp_rule(double a, double b, int n, func_type f){
int i = 1; double area = 0;
double n2 = n;
double h = (b-a)/(n2-1), x=a;
while(i <= n){
area = area + f(x)*pow(2,i%2 + 1)*h/3;
x+=h;
i++;
}
area -= (f(a) * h/3);
area -= (f(b) * h/3);
return area;
}
What I do is multiply each value of the function by either 2 or 4 (and h/3) with pow(2,i%2 + 1) and subtract off the edges as these should only have a weight of 1.
At first, I thought it worked just fine, however, when I compared it to my Trapezoidal Method function it was way more inaccurate which shouldn't be the case.
This is a simpler version of a code I previously wrote which had the same problem, I thought that if I cleaned it up a little the problem would go away, but alas. From another post, I get the idea that there's something going on with the types and the operations I'm doing on them which results in loss of precision, but I just don't see it.
Edit:
For completeness, I was running it for e^x from 1 to zero
\\function to be approximated
double f(double x){ double a = exp(x); return a; }
int main() {
int n = 11; //this method works best for odd values of n
double e = exp(1);
double exact = e-1; //value of integral of e^x from 0 to 1
cout << simp_rule(0,1,n,f) - exact;
The Simpson's Rule uses this approximation to estimate a definite integral:
Where
and
So that there are n + 1 equally spaced sample points xi.
In the posted code, the parameter n passed to the function appears to be the number of points where the function is sampled (while in the previous formula n is the number of intervals, that's not a problem).
The (constant) distance between the points is calculated correctly
double h = (b - a) / (n - 1);
The while loop used to sum the weighted contributes of all the points iterates from x = a up to a point with an ascissa close to b, but probably not exactly b, due to rounding errors. This implies that the last calculated value of f, f(x_n), may be slightly different from the expected f(b).
This is nothing, though, compared to the error caused by the fact that those end points are summed inside the loop with the starting weight of 4 and then subtracted after the loop with weight 1, while all the inner points have their weight switched. As a matter of fact, this is what the code calculates:
Also, using
pow(2, i%2 + 1)
To generate the sequence 4, 2, 4, 2, ..., 4 is a waste, in terms of efficency, and may add (depending on the implementation) other unnecessary rounding errors.
The following algorithm shows how to obtain the same (fixed) result, without a call to that library function.
template <typename func_type>
double simpson_rule(double a, double b,
int n, // Number of intervals
func_type f)
{
double h = (b - a) / n;
// Internal sample points, there should be n - 1 of them
double sum_odds = 0.0;
for (int i = 1; i < n; i += 2)
{
sum_odds += f(a + i * h);
}
double sum_evens = 0.0;
for (int i = 2; i < n; i += 2)
{
sum_evens += f(a + i * h);
}
return (f(a) + f(b) + 2 * sum_evens + 4 * sum_odds) * h / 3;
}
Note that this function requires the number of intervals (e.g. use 10 instead of 11 to obtain the same results of OP's function) to be passed, not the number of points.
Testable here.
The above excellent and accepted solution could benefit from liberal use of std::fma() and templatize on the floating point type.
https://en.cppreference.com/w/cpp/numeric/math/fma
#include <cmath>
template <typename fptype, typename func_type>
double simpson_rule(fptype a, fptype b,
int n, // Number of intervals
func_type f)
{
fptype h = (b - a) / n;
// Internal sample points, there should be n - 1 of them
fptype sum_odds = 0.0;
for (int i = 1; i < n; i += 2)
{
sum_odds += f(std::fma(i,h,a));
}
fptype sum_evens = 0.0;
for (int i = 2; i < n; i += 2)
{
sum_evens += f(std::fma(i,h,a);
}
return (std::fma(2,sum_evens,f(a)) +
std::fma(4,sum_odds,f(b))) * h / 3;
}
Hello I am solving trigonometry functions like sin(x) and cos(x) with Taylor Series Expansions
Problem: My values are not wrong just not very precise
My question is whether I can improve the accuracy of these functions, I think I have tried everything but I need your suggestions.
double trig::funcsin(int value)
{
sum = 0;
//summation
factorial fac;
for(int i = 0; i < 7; i++)
{
sum += pow((-1), i)*(((double)pow(value, (double)2*i+1)/(double)fac.fact((double)2*i+ 1)));
}
return sum;
}
double trig::funccos(int value)
{
factorial fac;
sum = 0;
for(int i = 0;i < 7;i++)
{
sum += (pow((-1), i)*((double)pow(value, (double)2*i)/(double)fac.fact((double)2*i)));
}
return sum;
}
Example:
Real: -0.7568024953
Mine: -0.73207
Real: -0.27941549819
Mine: -0.501801
Aslo as x becomes larger the output values become less precise at an exponential rate.
I am on GCC compiler, please give me suggestions
The following code demonstrates the Taylor series (about x==0) for the sin() function.
As you know, the sine function repeats an identical cycle for every 2*pi interval.
But the Taylor series is just a polynomial -- it needs a lot of terms to approximate a wiggly function like sine. And trying to approximate the sine function at some point far away from the origin will require so many terms that accumulated errors will give an unsatisfactory result.
To avoid this problem, my function starts by remapping x into a single cycle's range centered around zero, between -pi and +pi.
It's best to avoid using pow and factorial functions if you can instead cheaply update components at each step in the summation. For example, I keep a running value for pow(x, 2*n+1): It starts off set to x (at n==0), then every time n is incremented, I multiply this by x*x. So it only costs a single multiplication to update this value at each step. A similar optimization is used for the factorial term.
This series alternates between positive and negative terms, so to avoid the hassle of keeping track of whether we need to add or subtract a term, the loop handles two terms on each iteration -- it adds the first and subtracts the second.
Each time a new sum is calculated, it is compared with the previous sum. If the two are equal (indicating the updates have surpassed the sum variable's precision), the function returns. This isn't a great way to test for a terminating condition, but it makes the function simpler.
#include <iostream>
#include <iomanip>
double mod_pi(double x) {
static const double two_pi = 3.14159265358979 * 2;
const int q = static_cast<int>(x / two_pi + 0.5);
return x - two_pi * q;
}
double func_sin(double x) {
x = mod_pi(x);
double sum = 0;
double a = 1; // 2*n+1 [1, 3, 5, 7, ...]
double b = x; // x^a
double c = 1; // (2*n+1)!
const double x_sq = x * x;
for(;;) {
const double tp = b / c;
// update for negative term
c *= (a+1) * (a+2);
a += 2;
b *= x_sq;
const double tn = b / c;
const double ns = tp - tn + sum;
if(ns == sum) return ns;
sum = ns;
// update for positive term (at top of loop)
c *= (a+1) * (a+2);
a += 2;
b *= x_sq;
}
}
int main() {
const double y = func_sin(-0.858407346398077);
std::cout << std::setprecision(13) << y << std::endl;
}
I'm trying to write a function that runs a loop in C++ from R using Rcpp.
I have a matrix Z which is one row shorter than the matrix OUT that the function is supposed to return because each position of first row of OUT will be given by the scalar sigma_0.
The function is supposed to implement a differential equation. Each iteration depends on a value from the matrix Z as well as a previously generated value of the matrix OUT.
What I've got is this:
cppFunction('
NumericMatrix sim(NumericMatrix Z, long double sigma_0, long double delta, long double omega, long double gamma) {
int nrow = Z.nrow() + 1, ncol = Z.ncol();
NumericMatrix out(nrow, ncol);
for(int q = 0; q < ncol; q++) {
out(0, q) = sigma_0;
}
for(int i = 0; i < ncol; i++) {
for(int j = 1; j < nrow; j++) {
long double z = Z(j - 1, i);
long double sigma = out(j - 1, i);
out(j, i) = pow(abs(z * sigma) - gamma * z * sigma, delta);
}
}
return out;
}
')
Unfortunately I'm fairly certain it doesn't work. The function runs but the values calculated are incorrect - I've checked with simple examples in Excel and plain R-coding. I've stripped the main differentialequation apart trying to build it up step by step to see when the implementation i Excel and R using C++ starts to differ. Which seems to be when I start using the abs() function and power() function but I simply can't narrow the problem down. Any help would be greatly appreciated - also I might mention this is the first time for me using C++ and C++ along with R.
I think you want fabs rather than abs. abs operates on ints, while fabs operates on doubles / floats.
Greetings everyone. Having an issue compiling my script containing the following function. Three errors occur, all on the same line where I set distance += to distances [][]:
error C2108: subscript is not of integral type
error C2108: subscript is not of integral type
error C2297: '+=' : illegal, right operand has type 'double (*)[15]'
Assistance would be much appriciated.
double S_initial;
double distances [15][15];
double order [15];
void Initialize()
{
double x, y ,z;
double distance = 0;
for (int i = 0; i <= 14; i++)
{
x = order [i];
y = order [i + 1];
distance += distances [x][y];
}
S_initial = distance;
}
Well, the array subscripts x and y are not of an integral type like int, but of type double:
double x, y, z;
...
distance += distances[x][y];
And something like the 1.46534th element of an array doesn't make sense, so the compiler complains.
x and y are not integers... You need to pass integers as array subscripts.
Stop using double and use int instead.
Or if you have to use double in the order array, you need to decide how to round any non-integer value that may be found in order to a int. Math.Floor, Math.Ceiling etc.
You cannot use floating point numbers to index into arrays. Use int or even better size_t.
for (int i = 0; i <= 14; i++)
{
x = order [i];
y = order [i + 1]; /* when i = 14, you invoke UB */
distance += distances [x][y];
}
On to the second part:
double order [15];
is uninitialized and hence invokes UB, when used.