Transcendental Function Implementation (need help with output file now)

Hi, i have a project to do in my intro to computer science class, and here is the description.

You are to write a C++ program in Visual Studio 10.0 (VS 2010) and link and run the program as a Win32 console application that computes the transcendental functions, sin(x) and e(x) [called sin(x) and exp(x) in <cmath>, respectively], for a given subset of a range of values of type double. The program should accept a range of values and an increment size from the user. The values of the given interval should be displayed along with the <cmath> sin(x) and exp(x) functions, your sin(x), and two versions of your exp(x) functions; the two versions of your exp(x) function. For the purpose of specification, the names of your functions will be called my_sin() and my_exp() so that they can be distinguished from the <cmath> ones. You need not know what these mean. Only follow the formulas below for your functions and use the <cmath> functions for comparison of correct values.


The problem is i dont know where or how to start. i have never taken calculus before so im pretty much completely lost as to how to start or figure out how to make this

I also cant find any similar examples of such a thing in C++ online either, so i have really no guidance at all

Im not asking for someone to do this for me, but more like im asking for hints and guidance as to how to approach this, and any sample code would be appreciated as well as i cant find any

also, here is a link to the full specifications of the project, so you guys can better understand where i am coming from
http://www.mediafire.com/view/?ab4rj3p0odr8yh4
Last edited on
Also, i should have posted what i have so far

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <iostream>
#include <fstream>
#include <cmath>
#include <iomanip>
using namespace std;
double my_sin(double);
double my_exp(double);
int main()



{
	ofstream output;

	double lowerbound, upperbound, increment;
	char response;

	output.open("output.txt"); //if output.txt does not exist it is created
							 //if it does exist the existing data is wiped out and a new set written to it
	do
	{
	output << "-----------" << endl;
	cout << "enter lower bound: ";
	cin >> lowerbound;
	cout << "enter upper bound: ";
	cin >> upperbound;
	cout << "enter increment: ";
	cin >> increment;
	output << "lower and upper bounds: "<< lowerbound << "    " << upperbound << endl;
	output << " increment: " << increment << endl;

	output << setiosflags(ios::showpoint)<< setprecision(7); //shows decimal places in the output. setprecision is how many numbers it shows after the decimal

	for(double x = lowerbound; x <= upperbound; x += increment )
		{
			output << setw(7) << x << setw(14) << sin(x) << endl;
		}
	
	cout << "again (y/n)? ";
	cin >> response;

	}while(response  == 'y' || response == 'Y' );

	/*output << "ABC\n";
	output << "DEF\n";
	output << "GHI\n";
	*/
	output.close();


	cout << "finished\n";

	return 0;
}
The key to this problem is that you have to find the sum of an infinite series. Luckily, each term is smaller than the preceding one, (at least for small values of x) and so you don't need to go on to infinity. Probably something like 5 to 20 terms may be sufficient, depending on the accuracy required.

There have been several previous questions on a similar topic, but the sample code is not necessarily to be recommended, except as an overview of some of the concepts involved.

Ah, I see now at the top of page 2 of the PDF document, the required formula is given, and it is stated that you must use the first 50 terms.

Actually, it's deeply disappointing to read this in the PDF specifications:
Quote: "You must implement a factorial function, factorial(n), and a power function, power(x, n), and do NOT use any other library functions. You MUST write their definitions."

The reason I say that is that both the powers of x, and the factorials can be derived from the values used when calculating the preceding term. If you use a separate function, instead of just one or two multiplications, you will end up doing very many, and re-calculating the same numbers over and over (and over) again. The results will still be the same, but it is an extremely inefficient approach.

I'd read the fine print carefully. It may be that you have to define these functions, but might not be compelled to actually use them.
Last edited on
closed account (D80DSL3A)
Your shell of code looks fairly solid. Is it the math that is stopping you?

I agree with Chervil it's a shame that factorial and power functions must be used.
It is much more efficient to simply update the values of N! and x^N each iteration, than to calculate the values from scratch.

That said, I will assume that you MUST use these functions. Use of these functions is good in 1 respect. They make writing the my_sin() and py_exp() functions a little simpler.

I advise that you write the factorial function to return a double, not an integer, to avoid range limit issues. In fact, I'll give you that one:
1
2
3
4
5
6
7
double factorial( int N )// find N! and return as a double value
{
    double retVal = 1.0;
    for( int n = 2; n <= N; ++n )
        retVal *= (double)n;
    return retVal;
}

Can you write the required power() function?
The prototype should be:
 
double power( double x, int n );// returns x^n 

Get these 2 functions added to your project and I will be happy to help you with the my_sin() and my_exp() functions.
Thank you guys for the replies and help.

@ fun2code

Yes, it is mostly the math that is stopping me, as i have not taken a calculus class yet, which stumps me as to why they would put a calculus problem in an intro to programming class, which is usually taken before calculus, so terms like fractorial and transcendental have no meaning to me as i dont know what they mean. apart from what me and my partner have already figured out. Coding and some basics in C++ on the other hand i believe i have the hang of.


ill post the code in a few minuets, i added the function you posted ( i put it before int main, since thats what are professor said to put functions), just waiting for my partner to get back from class, as we are doing this together since two heads are better than one lol

also a question about visual basic 2012 if you guys might know the answer to, we just switched from visual basic 2010 to 2012, and i cant seem to get the little windows at the bottom to appear that usually tells you where an error is, as that windows was rather helpful
Last edited on
We are still unsure what we are supposed to do with the factorial function that fun2code wrote, like where it should be called within the code

we were thinking it should be called sometime after output.open("output.txt") on line 18

Last edited on
Alright here is what we have so far

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>
#include <fstream>
#include <cmath>
#include <iomanip>
using namespace std;

double fractorial(int);

int main()

{
	ofstream output;

	double lower, upper, increment, y;
	char response;

	output.open("output.txt"); //if output.txt does not exist it is created
							 //if it does exist the existing data is wiped out and a new set written to it
	do
	{
	output << "-----------" << endl;
	cout << "enter lower bound: ";
	cin >> lower;
	cout << "enter upper bound: ";
	cin >> upper;
	cout << "enter increment: ";
	cin >> increment;
	output << "lower and upper bounds: "<< lower << "    " << upper << endl;
	output << " increment: " << increment << endl;

	output << setiosflags(ios::showpoint)<< setprecision(7); //shows decimal places in the output. setprecision is how many numbers it shows after the decimal

	output << setw(7) << "X" << setw(14) << "sin(x) " << setw(21) << "my_sin(x)" << setw(28) << "e(x)" << setw(35) << "my_e1(x) " << setw(42) << "my_e(x)" << endl;

	for(double x = lower; x <= upper; x += increment )
		{
			output << setw(7) << x << setw(14) << sin(x) << setw(21) << y << setw(35) << exp(x) << endl;
		}
	
	
	cout << "again (y/n)? ";
	cin >> response;

	}while(response  == 'y' || response == 'Y' );
	
	output.close();


	cout << "finished\n";

	return 0;
}
double fractorial( int x)
{
	double y = 1.0;
	for( int n = 2; n <= x; ++n)
		y *= (double)n;
	return y;
}


But we ran into problems with the output file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
lower and upper bounds: 0    1
 increment: 0.1
      X       sin(x)             my_sin(x)                        e(x)                          my_e1(x)                                    my_e(x)
0.0000000     0.0000000             1.000000                           1.000000
0.1000000    0.09983342             1.000000                           1.105171
0.2000000     0.1986693             1.000000                           1.221403
0.3000000     0.2955202             1.000000                           1.349859
0.4000000     0.3894183             1.000000                           1.491825
0.5000000     0.4794255             1.000000                           1.648721
0.6000000     0.5646425             1.000000                           1.822119
0.7000000     0.6442177             1.000000                           2.013753
0.8000000     0.7173561             1.000000                           2.225541
0.9000000     0.7833269             1.000000                           2.459603
1.000000     0.8414710             1.000000                           2.718282
closed account (D80DSL3A)
Good. Job. Any progress with the power function?

Both factorial and power() would be called in your my_sin(), once you start writing it that is.

I see that you changed my variable name from retVal to y in the factorial().
This is fine. You know that the y in the factorial() is completely unrelated to the y in main() used on line 27, right?

Do you see where the factorial() and power() functions would be used in the formulas given for the power series for e^x and sin(x) ?
Let's take this from the basics.

Factorial of x
The symbol used is an exclamation mark, thus 6 factorial (or the factorial of 6) is represented as 6!
It is found by multiplying together all the integers from 1 to n
thus 6! = 1 * 2 * 3 * 4 * 5 * 6 = 720.

Power of x
When writing by hand, we would use a superscript, x2 = x * x
or x3 = x*x*x and so on.
But it is often more convenient to use the ^ symbol to mean "raised to the power of", such as x^5 = x5 = x * x * x * x * x
For example, when x = 3, x^5 = 243.

Those are the building blocks which we will use. The task is to use the Taylor series expansion for sin(x) (and other functions) to calculate the actual value of the function.

The good news is that they are all very similar. So if you can do sin(x), then cos(x) and ex are almost the same. So the effort required to do all of them is only a tiny bit more than it is to do just one.

to be continued...
Last edited on
We will be working with values in radians, not degrees. That means instead of saying sin(30) degrees we use sin(PI/6) radians, and so on. Don't worry about that, it's the way the built-in functions work too. If you need to convert degrees to radians there's a simple conversion factor of PI/180.

Now let's calculate the sin of 30o or PI/6.
This gives x = 0.52359878 = 30*PI/180 = PI/6.

The correct answer is exactly 0.5, so we can see quickly whether our method is sensible or not.

The required series is this: sin(x) = x - x^3/3! + x^5/5! - x^7/7! + ...

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>

const double PI = 3.1415926535897932385;

double sin(double x); // Declare function prototype

int main()
{
    using std::cout;
    using std::endl;

    cout.precision (20);

    double x = PI/6;
    cout << "  x      = " << x << endl;
    cout << "  sin(x) = " << sin(x) << endl;
    return 0;
}

double sin(double x) // Provide the full definition of the function
{
    // sin(x) = x - x^3/3! + x^5/5! - x^7/7! + ...

    double total = 0;

    total += x;                             // first term is     x
    total -= x*x*x/(2*3);                   // second term is  - x^3/3!
    total += x*x*x*x*x/(2*3*4*5);           // third term is   + x^5/5!
    total -= x*x*x*x*x*x*x/(2*3*4*5*6*7);   // fourth term is  - x^7/7!
    total += x*x*x*x*x*x*x*x*x/(2*3*4*5*6*7*8*9);      // etc.
    total -= x*x*x*x*x*x*x*x*x*x*x/(2*3*4*5*6*7*8*9*10*11);

    return total;
}

Output:
  x      = 0.5235987755982988156
  sin(x) = 0.4999999999999643064

The real job is to change the sin() function so that instead of working out each term separately, you use a loop to do so, with some pretty straightforward code to find and accumulate each term.
Last edited on
Also, you would normally derive each term from the preceding one.
Thus:
1
2
 + x*x*x*x*x/(2*3*4*5);           // third term is   + x^6/5!
 - x*x*x*x*x*x*x/(2*3*4*5*6*7);   // fourth term is  - x^7/7! 


1
2
3
4
5
term1 = x;                
term2 = - term1 * x*x/(2*3);                
term3 = - term2 * x*x/(4*5);                
term4 = - term3 * x*x/(6*7);  
term5 = - term4 * x*x/(8*9);

That's certainly the general approach I'd use. Whether or not you are permitted to use such a method I cannot say for sure.

If in doubt, use the separate functions. They will tend to make the code more readable, which is an important part of writing good program code.

Also, you should not use double variables in a for loop like this:

for(double x = lower; x <= upper; x += increment )

Doubles are stored as binary fractions and cannot represent every real number. For this reason any of the equality operators will fail ( or fail on the last value).

It is much better to use integers in the loop initialisation, end condition, and increment - then cast these to double inside the loop.

Also, if you make use of std::toupper you can avoid this:

}while(response == 'y' || response == 'Y' );

and do this instead:

1
2
3
4
5
#include <locale>

response = std::toupper(response);

}while(response == 'Y' );
Last edited on
Topic archived. No new replies allowed.