I'm having problem writing code for a program that estimates the value of the mathematical constant e by using this formula e= 1 + 1/1! + 1/2!...
I just cant get this to work. Can someone please help

Hmm ... start by writing a recurisve function to find the factorial of a number. There's a tutorial on recursion in either the C++ or the Computer Science section of this site - I forget which. You should also be able to find this function by doing a quick google search. Then just add 1/ to your factorial equation and it should do the trick ;)

I know that I'm breaking the rule not to make anybody's homwork.
But since the answer is so simple I can not help it to post a solution

#include <iostream>

double fakt(int i)
{ 
  if ( i == 1 )
     return 1.0;
  return fakt( i -1 ) * i;
}

int main() {
   double e = 1.0;
   for ( int i = 1; i < 4000; i++ ) {
      e += 1.0 / fakt(i);
   }
   std::cout << " e = " << e << std::endl;
   return 0;
}

K.

>for ( int i = 1; i < 4000; i++ ) {
>e += 1.0 / fakt(i);
Wow, I'm impressed if you can fit up to 3999! into a double. I just get undefined behavior when the limit of double is exceeded. :rolleyes:

@ Narue: you are right that 170! is the largest nr. that fits into a double.
but with my compiler the result is still correct because fact() simply returns inf for larger numbers then 170 and 1/inf returns 0.0 (btw I'm using gcc )
K.

>but with my compiler the result is still correct
That's nice, but your code is still wrong even if the compiler that you use happens to interpret "undefined" as something intelligent.

>but with my compiler the result is still correct
That's nice, but your code is still wrong even if the compiler that you use happens to interpret "undefined" as something intelligent.

I did not mean to insist on my code being correct. My statement was meant to explain why I did not recognize the mistake in the first place.
K.

Since this is not a for-hire service, I think it's good that we watch over each other, but code snippets should be seen as starting points or suggestions, not finished product. None of the snippets or suggestions I make are ones I've built and tested, only ideas to get the thread-opener's juices flowing.

Zuk offered a snippet that is boatloads farther down the path than where the poster started. The rest should be "left to the student" as it were.

Some of my posts have been nit picked for syntax or stuff that misses the bigger picture; but read them for the idea not the actual product.

Naru, your posts are great but please try to have a little patience with those of us who can't devote as much time to posts as you. Thanks!

>explain why I did not recognize the mistake in the first place.
I can understand not knowing that floating-point overflow is undefined, but it should be immediately obvious that a double couldn't possibly hold a factorial anywhere close to 3999!.

>but code snippets should be seen as starting points or suggestions, not finished product.
I agree. Unfortunately, those that we help aren't quite so forgiving. They have a tendency to see code we post as set in stone answers that "must" be correct. As such, rather than end up teaching bad habits, we should try to be as accurate and correct as possible.

>None of the snippets or suggestions I make are ones I've built and tested
That's your choice. I prefer to only post code that I've made sure works as expected. However, you should mention that your code wasn't tested and you only "hope" that it works.

>only ideas to get the thread-opener's juices flowing.
That's fine, I do it myself. But I make sure that the example is still correct so that the juices aren't sour.

>Some of my posts have been nit picked for syntax or stuff that misses the bigger picture
That's a rather narrow view I think. It seems to me that it was you who missed the bigger picture. If you don't want to be nitpicked on syntax then give pseudocode. It still conveys the idea and avoids people like me who think that teachers should make an attempt at being correct because they're viewed as role models.

>but please try to have a little patience with those of us who can't devote as much time to posts as you.
I have very little time to devote to posts despite what you may think, but I still manage to check my answers. Thus I have very little patience for people who are either too lazy or too arrogant to make sure that they're right.

> but it should be immediately obvious that a double couldn't possibly hold a factorial anywhere close to 3999!.
sorry for beeing that stupid.
K.

>sorry for beeing that stupid.
I wouldn't say stupid because that would be mean without being constructive. But it is always a good idea to know what the limitations of your system are, and even better the limitations placed on you by the language standard. Then you can more easily determine if you exceed those limitations using common sense. It seems to me that the problem was just a lack of information concerning the size of a double. The fact that your implementation didn't throw a floating-point exception but instead did something nice didn't help at all. It just hid the fact that your code was doing something it wasn't supposed to do.

Actually I do ( did ) know the range of numbers that can be represented by a double. What I underestimated ( quite a lot I must admit ) is the level of recoursion that occurs in computing the factorial of a number. In the last 15 years or so of programming C and C++ i have never even come close to the upper limits of a double. From now on I will bear in mind that even a double has a limit that has to be considered.
K.

>What I underestimated ( quite a lot I must admit ) is the level of recoursion that occurs in computing the factorial of a number.
Factorials grow incredibly fast. Whenever you have a sequence like that, you need to be aware of your limits. :)

I've been playing along at home; any criticisms for this?

#include <stdio.h>
#include <math.h>
#include <float.h>
#include <limits.h>

int factorial(unsigned long n, unsigned long *result)
{
   unsigned long i;
   for ( *result = 1, i = 2; i <= n; i++ )
   {
	  if ( *result > ULONG_MAX / i )
	  {
		 printf("overflow at n = %lu, ", n);
		 return 0;
	  }
	  *result *= i;
   }
   //printf("n = %lu, result = %lu\n", n, *result);
   return 1;
}

double estimate_e(unsigned long iterations)
{
   double e = 1.0;
   unsigned long i, denominator;
   for ( i = 1; i < iterations && factorial(i, &denominator); ++i )
   {
	  e += 1.0 / denominator;
   }
   return e;
}

int main()
{
   double epsilon = 1E-10; /* or specify your own pickiness level */
   double e = exp(1.0);
   unsigned long i;
   for ( i = 0; i < 20; ++i )
   {
	  double estimate = estimate_e(i);
	  printf("estimate_e(%2d) = %.*g\n", i, DBL_DIG, estimate);
	  if ( fabs(e - estimate) <= epsilon * fabs(e) )
	  {
		 puts("close enough");
		 break;
	  }
   }
   printf("e = %.*g\n", DBL_DIG, e);
   return 0;
}

/* my output
estimate_e( 0) = 1
estimate_e( 1) = 1
estimate_e( 2) = 2
estimate_e( 3) = 2.5
estimate_e( 4) = 2.66666666666667
estimate_e( 5) = 2.70833333333333
estimate_e( 6) = 2.71666666666667
estimate_e( 7) = 2.71805555555556
estimate_e( 8) = 2.71825396825397
estimate_e( 9) = 2.71827876984127
estimate_e(10) = 2.71828152557319
estimate_e(11) = 2.71828180114638
estimate_e(12) = 2.71828182619849
estimate_e(13) = 2.71828182828617
close enough
e = 2.71828182845905
*/

>any criticisms for this?
You code looks a lot like C but you use the single line comment style without mentioning C99. ;) Other than that I have no criticisms except for the use of epsilon instead of DBL_EPSILON. Your value of 1E-10 exceeds the standard minimum requirement by 1 IIRC, so it isn't technically portable.

>>any criticisms for this?
>You code looks a lot like C
It is.

>but you use the single line comment style without mentioning C99. ;)
True enough. I came back to edit that debug line out, but chose not to.

>Other than that I have no criticisms except for the use of epsilon instead of DBL_EPSILON.
I had initially used DBL_EPSILON, but the results are the other way.:D

estimate_e( 0) = 1
estimate_e( 1) = 1
estimate_e( 2) = 2
estimate_e( 3) = 2.5
estimate_e( 4) = 2.66666666666667
estimate_e( 5) = 2.70833333333333
estimate_e( 6) = 2.71666666666667
estimate_e( 7) = 2.71805555555556
estimate_e( 8) = 2.71825396825397
estimate_e( 9) = 2.71827876984127
estimate_e(10) = 2.71828152557319
estimate_e(11) = 2.71828180114638
estimate_e(12) = 2.71828182619849
estimate_e(13) = 2.71828182828617
overflow at n = 13, estimate_e(14) = 2.71828182828617
overflow at n = 13, estimate_e(15) = 2.71828182828617
overflow at n = 13, estimate_e(16) = 2.71828182828617
overflow at n = 13, estimate_e(17) = 2.71828182828617
overflow at n = 13, estimate_e(18) = 2.71828182828617
overflow at n = 13, estimate_e(19) = 2.71828182828617
e = 2.71828182845905

That's another reason I added the comment, "or specify your own pickiness level".

>Your value of 1E-10 exceeds the standard minimum requirement by 1 IIRC, so it isn't technically portable.
This is new to me... could you expand on this please?

"I have very little time to devote to posts despite what you may think, but I still manage to check my answers. Thus I have very little patience for people who are either too lazy or too arrogant to make sure that they're right."

Hee hee. Well, I'm both lazy AND arrogant.

>Hee hee. Well, I'm both lazy AND arrogant.
:D

>This is new to me... could you expand on this please?
I don't have my copy of the standard available at the moment, but if I remember it right, 1E-9 is the implementation limit imposed by the committee. IEEE expands this to something like 2.220...E-16. The details are lost to me right now though, sorry. :o

This article has been dead for over six months. Start a new discussion instead.