Aiyaiyai... (C++ & math help)
Ok, I don't know what my Computer Science 1030 professor has been smoking, but it's probably not legal.
Here's the deal: I have an programming assignment due Friday for this guy, in which he wants us to write a C++ program that will approximate the value of pi using the Bailey‐Borwein‐Plouffe formula, which goes like this:
We had previously done an in-class example of a similar program that computed an approximation of e (base of a natural logarithm). It used a main method that consisted of three sub-methods; one for input, one for computation, and one for output. Basic stuff.
I copied the source code for this program and rewrote the computation method using the following algorithm, which implements the above formula given a positive integer value K:
double sum = 0, pi = 0;
int k = 0;
while (k < K) {
sum = (1/(16^k))*((4/(8*k+1)) - (2/(8*k+4)) - (1/(8*k+5)) - (1/(8*k+6)));
pi += sum;
k++;
}
return pi;
}
I compile, catch a few compiler errors, edit, and compile again, then run the program. The goal is that by inputting 10 as the value for K, I should have an approximation of pi for the first ten digits to the right of the decimal point. However, the value of pi is 3.141..., and the results I keep getting are screwed beyond comprehension. Numbers between 1 and 10 get me a number in the ballpark of 0.20..., while numbers greater than 14 or so give me some weird string 1.INF00000000 (which I can only assume is an error message of some sort.)
I went onto Wikipedia to find out more about this formula, and it said that the formula is used for calculating binary or hexadecimal digits... neither of which has been covered in class yet, and my professor gave no indication in the information sheet he gave us that we were supposed to use these data types. I have no friggin clue whether the errors I keep getting are logic errors from the formula or just becuase I'm using the formula in the wrong way. I'm about close to giving up, if I can't get a straight answer out of my professor during class on Tuesday or Thursday, I'm screwed.
Anyone here got any ideas?
_________________
"Yeah, so this one time, I tried playing poker with tarot cards... got a full house, and about four people died." ~ Unknown comedian
Happy New Year from WP's resident fortune-teller! May the cards be ever in your favor.
cyberscan
Veteran
Joined: 16 Apr 2008
Age: 56
Gender: Male
Posts: 1,296
Location: Near Panama, City Florida
I played a bit with your code, and I think this might help. Actually, it gives the answer outright
#include<stdio.h>
#include<math.h>
// compile with cc nameoffile.c -lm
//to link in the math library
double ComputeApproximation(double K) {
double sum = 0, pi = 0;
double k = 0;
while (k < K) {
printf("k=%f\r\n", k);
sum = (1/pow(16,k))*((4/(8*k+1)) - (2/(8*k+4)) - (1/(8*k+5)) - (1/(8*k+6)));
pi += sum;
k++;
}
return pi;
}
int main()
{
double result=0;
result=ComputeApproximation(10);
printf("The result is %f\r\n", result);
return 0;
}
_________________
I am AUTISTIC - Always Unique, Totally Interesting, Straight Talking, Intelligently Conversational.
I am also the author of "Tech Tactics Money Saving Secrets" and "Tech Tactics Publishing and Production Secrets."
cyberscan
Veteran
Joined: 16 Apr 2008
Age: 56
Gender: Male
Posts: 1,296
Location: Near Panama, City Florida
if you are not for some reason allowed to link to the math library, you can also create your own pow function
double pow(double x, double y){
double yi=1;
double r1 = x;
if(y==0) return 1;
if(y==1) return x;
while(yi<y){
r1=r1*x;
yi++;
}
return r1;
}
I did notice that the precision of the division operator is limited when my program would not calculate any more precise than 3.141593, I suspected such. Therefore in the while loop of the ComputeApproximation function, I added
printf("(1/(16 ^ %f))=%f\r\n", k, (1/pow(16,k)));
When I ran the program, I got the following:
(1/(16 ^ 0.000000))=1.000000
(1/(16 ^ 1.000000))=0.062500
(1/(16 ^ 2.000000))=0.003906
(1/(16 ^ 3.000000))=0.000244
(1/(16 ^ 4.000000))=0.000015
(1/(16 ^ 5.000000))=0.000001
(1/(16 ^ 6.000000))=0.000000
(1/(16 ^ 7.000000))=0.000000
(1/(16 ^ 8.000000))=0.000000
(1/(16 ^ 9.000000))=0.000000
(1/(16 ^ 10.000000))=0.000000
(1/(16 ^ 11.000000))=0.000000
(1/(16 ^ 12.000000))=0.000000
(1/(16 ^ 13.000000))=0.000000
(1/(16 ^ 14.000000))=0.000000
The result is 3.141593
I hate to say it, but you may need to write your own long division routine ;-( for better precision.
_________________
I am AUTISTIC - Always Unique, Totally Interesting, Straight Talking, Intelligently Conversational.
I am also the author of "Tech Tactics Money Saving Secrets" and "Tech Tactics Publishing and Production Secrets."
I did notice that the precision of the division operator is limited when my program would not calculate any more precise than 3.141593, I suspected such. Therefore in the while loop of the ComputeApproximation function, I added
printf("(1/(16 ^ %f))=%f\r\n", k, (1/pow(16,k)));
......
I think you're just printing it with to less precision to see the real value, using cout << 1/pow(16.0 , k) << endl I get to see it correctly (don't forget to include the iostreams)
My solution
I made the flowing (quite a revision of your code, and quite compact):
double pi = 0;
for ( int k = 0; k < K; k++)
pi += ( 1 / pow( 16.0 , k ) ) * ( ( 4 / ( 8.0 * k + 1 ) ) - ( 2 / ( 8.0 * k + 4 ) ) - ( 1 / ( 8.0 * k + 5 ) ) - ( 1 / ( 8.0 * k + 6 ) ) );
return pi;
}
While the next piece of code does the same, it just looks more like your own code
double sum = 0, pi = 0;
int k = 0;
while( k < K) {
sum = ( 1 / pow( 16.0 , k ) ) * ( ( 4 / ( 8.0 * k + 1 ) ) - ( 2 / ( 8.0 * k + 4 ) ) - ( 1 / ( 8.0 * k + 5 ) ) - ( 1 / ( 8.0 * k + 6 ) ) );
pi += sum;
k++;
}
return pi;
}
comments on your code
As said the main problem with the code was using ^ (which is a totally different C operator) instead of pow( base , power). Also there were integer divisions (e.g. 1/(8*k + 1) with k an integer) which probably would give not the right results for you. Integer/integer divisions will round down!! ! That's why the other ppl have changed k to a double, and I have made 8 a non integer by changing it into 8.0.
about binary and hexadecimal
On the binary/hexadecimal thing, they are just other ways of representing numbers. Binary uses only 1 and 0 as digits (we use 0,1,2,3,4,5,6,7,8 and 9) and is the way computer uses, as it is easier to make that using our ten digits. Hexadecimal uses 16 digits, and is used mainly by programmers, because hexadecimal can easily be converted to binary (1 hexa digit = 4 binary digits).
edits: improved the readability and added the looks more like code piece
AspiInLV
Blue Jay
Joined: 6 Jan 2010
Age: 50
Gender: Male
Posts: 88
Location: The Unemployment capitol of the US
the Use of template functions
//allow for squares of any type
template<typename T>
T Square(T x)
{
return x * x;
}
<math.h> allows the user to throw number overflow or under flow exceptions.
there is also the long double datatype
You seriously need to consider a new line of work: by the time you graduate, your job will most likely be in India.
Last edited by AspiInLV on 25 Jan 2010, 11:28 am, edited 1 time in total.
I think the problem was with that stupid ^ operator. I'm going to try using the math library and that pow() function instead. I'll keep you guys posted.
UPDATE: Baka desu! (I'm an idiot!) Turns out it was the ^ operator. I went ahead and wrote a pow() function, and entered that into my equation. That ended up getting me close to pi, but I was still geting the error for values greater than 8. I changed all of the values in my equation to doubles and it still wouldn't work. Finally I took the pow() method and changed both inputs and the output to double, and it worked fine.
I'll have to remember the operators better in the future. Thanks guys.
_________________
"Yeah, so this one time, I tried playing poker with tarot cards... got a full house, and about four people died." ~ Unknown comedian
Happy New Year from WP's resident fortune-teller! May the cards be ever in your favor.
The integer division is another issue, as mentioned by another poster. Either make k a double, or put .0 after the constants to force double precision. Unlike other languages, C/C++ does not have a dedicated integer division operator. If both the dividend and divisor are integer, "/" will perform integer division and you'll lose any fractional part of the quotient.
The integer division is another issue, as mentioned by another poster. Either make k a double, or put .0 after the constants to force double precision. Unlike other languages, C/C++ does not have a dedicated integer division operator. If both the dividend and divisor are integer, "/" will perform integer division and you'll lose any fractional part of the quotient.
Already took care of that. Thanks though.
_________________
"Yeah, so this one time, I tried playing poker with tarot cards... got a full house, and about four people died." ~ Unknown comedian
Happy New Year from WP's resident fortune-teller! May the cards be ever in your favor.
cyberscan
Veteran
Joined: 16 Apr 2008
Age: 56
Gender: Male
Posts: 1,296
Location: Near Panama, City Florida
I did notice that the precision of the division operator is limited when my program would not calculate any more precise than 3.141593, I suspected such. Therefore in the while loop of the ComputeApproximation function, I added
printf("(1/(16 ^ %f))=%f\r\n", k, (1/pow(16,k)));
......
I think you're just printing it with to less precision to see the real value, using cout << 1/pow(16.0 , k) << endl I get to see it correctly (don't forget to include the iostreams)
My solution
I made the flowing (quite a revision of your code, and quite compact):
double pi = 0;
for ( int k = 0; k < K; k++)
pi += ( 1 / pow( 16.0 , k ) ) * ( ( 4 / ( 8.0 * k + 1 ) ) - ( 2 / ( 8.0 * k + 4 ) ) - ( 1 / ( 8.0 * k + 5 ) ) - ( 1 / ( 8.0 * k + 6 ) ) );
return pi;
}
While the next piece of code does the same, it just looks more like your own code
double sum = 0, pi = 0;
int k = 0;
while( k < K) {
sum = ( 1 / pow( 16.0 , k ) ) * ( ( 4 / ( 8.0 * k + 1 ) ) - ( 2 / ( 8.0 * k + 4 ) ) - ( 1 / ( 8.0 * k + 5 ) ) - ( 1 / ( 8.0 * k + 6 ) ) );
pi += sum;
k++;
}
return pi;
}
comments on your code
As said the main problem with the code was using ^ (which is a totally different C operator) instead of pow( base , power). Also there were integer divisions (e.g. 1/(8*k + 1) with k an integer) which probably would give not the right results for you. Integer/integer divisions will round down!! ! That's why the other ppl have changed k to a double, and I have made 8 a non integer by changing it into 8.0.
about binary and hexadecimal
On the binary/hexadecimal thing, they are just other ways of representing numbers. Binary uses only 1 and 0 as digits (we use 0,1,2,3,4,5,6,7,8 and 9) and is the way computer uses, as it is easier to make that using our ten digits. Hexadecimal uses 16 digits, and is used mainly by programmers, because hexadecimal can easily be converted to binary (1 hexa digit = 4 binary digits).
edits: improved the readability and added the looks more like code piece
You're right I was looking over the OP, and it was intended to be C++. For some reason, I chose C. I guess that is because I reverted to my first programming language
_________________
I am AUTISTIC - Always Unique, Totally Interesting, Straight Talking, Intelligently Conversational.
I am also the author of "Tech Tactics Money Saving Secrets" and "Tech Tactics Publishing and Production Secrets."
UPDATE: Baka desu! (I'm an idiot!) Turns out it was the ^ operator. I went ahead and wrote a pow() function, and entered that into my equation. That ended up getting me close to pi, but I was still geting the error for values greater than 8. I changed all of the values in my equation to doubles and it still wouldn't work. Finally I took the pow() method and changed both inputs and the output to double, and it worked fine.
I'll have to remember the operators better in the future. Thanks guys.
Every thing but an idiot, those are easy pitfalls when learning to program. I've seen quite a lot of ppl get stuck on the same issue (I helped my fellow math students in a little programming course). Special integer integer division is quite useful, though as in c++ where it is the same operator it is something you need to be aware of. I've seen a lot of ppl also doing that wrong (trying to sum 1/(k*k) with k as int from -100 to 100)
The problem with returning an int from the pow function is/was (probably) again the int/int division. As the code was 1 / pow(....) * ( a lot more). the compiler reads from left to right, so the division is done first and as pow returns an int and 1 is an int, it uses int/int division which ignores the fractional part. And as pow(...) is larger than 1 (except for the first time) 1/pow(....) will be 0
Every thing but an idiot, those are easy pitfalls when learning to program.
Even worse wth C, which uses the same operator (/) for both floating-point and integer division, and the circumflex/caret operator (^) for bitwise exclusive-or, instead of exponentiation.
If you plan to continue programming in C (or C++, not much difference in fundamental behavior), find a good reference (e.g., Stroustrup) and read the section on implicit type conversions (especially "promotion").
And never be afraid to ask someone else to look over your own malfunctioning code. Quite often, you'll find your own error in the process of explaining its operation.
#include<cmath>
not :
#include<math.h>
Also:
#include<cstdio>
I was wondering why that didn't work. I ended up writing a small method for exponentation on my own which incorporated a while loop. It works fine for the task at hand. I'll remember the <cmath> and <cstdio> classes in the future.
_________________
"Yeah, so this one time, I tried playing poker with tarot cards... got a full house, and about four people died." ~ Unknown comedian
Happy New Year from WP's resident fortune-teller! May the cards be ever in your favor.
Similar Topics | |
---|---|
Fifth grade math teacher's Facebook |
Yesterday, 5:41 am |
Math question supposed to reveal if someone is autistic |
23 minutes ago |