Code involving factorials and a given value
3 ビュー (過去 30 日間)
Voss 2022 年 5 月 1 日
@Ryan Johnson Using a while loop to solve this problem is a perfectly good approach. The main thing you need to change is the while condition. You have while i<=x, but the variable i is the "loop iteration counter", if you will (i.e., it's incremented by one on each iteration), so that condition is saying to iterate a certain fixed number of times, but if you knew how many iterations it would take beforehand, you'd use a for loop rather than a while loop. Instead, the condition should be based on the running product of the integers, which is n, since the objective is to iterate until that product reaches a certain fixed value. So just change that condition to while n<=x and you're good to go:
% prompt= 'Enter value of x: ';
x = 5000;
% while i<=x
(I also fixed up the fprintf statement. And you could use the input function to take the value of x from the user.)
その他の回答 (2 件)
John D'Errico 2022 年 5 月 1 日
Now that you have a looped solution, let me show how to solve the problem more directly. There are actually several solutions I can think of.
The Stirling approximation for a factorial is a simple one.
In there, we would find a good approximation for the factorial function.
factorial(n) ~~ sqrt(2*pi*n)*n^n/exp(n)
This is a pretty good approximation. Thus
n = 0:10;
stir = @(n) sqrt(2*pi*n).*n.^n.*exp(-n);
In fact, you should see the Stirling approxiamtion will consistently under-predict the factorial function. You can probably learn that from a second order approximation to the factorial, by seeing that the next term in a series would be always positive. But stir is itself pretty good as an approximation.
So take the log of that. That is pretty simple, as long as we are careful.
log(factorial(n)) ~~ log(pi)/2 + log(2)/2 + log(n)/2 + n*log(n) - n
How can we use this?
logfact = @(n) log(pi)/2 + log(2)/2 + log(n)/2 + n.*log(n) - n;
Now use fzero. Suppose you want to compute the smallest n, such that factorial(n) is larger than 5000? We need only a call to fzero now.
facttarget = 5000;
ntarget = floor(fzero(@(n) logfact(n) - log(facttarget),[eps,100]))
Sigh. Is this overkill? Perhaps. A simpler solution can be found from a table lookup. If we recognize that any factorial above factorial(170) will overflow double precision arithmetic, then we could just compute the logs of all the factorials, as:
N = (1:170)';
logfactlist = cumsum(log(N));
Now, suppose we wanted to find the smallest value of n such that factorial(n) is at least some target? This should work:
nsolve = @(target) ceil(interp1(logfactlist,N,log(target),'linear'));
nsolve([5000 5040 5041])
In fact, this function will work as high up as factorial(170). It would fail beyond that point, since I only generated a lookup table that went that high.
Can you solve the problem more simply, using a while loop? Well, you already got that answer.