memory overflow with double factorial function

조회 수: 14 (최근 30일)
Harry Rogers
Harry Rogers 2020년 10월 9일
편집: Walter Roberson 2024년 7월 22일
I am trying to create a recursive formula to calculate the double factorial of a number, n. The code I have come up with currently is as follows:
function [DFact] = DFactorialRec(n)
DFact = n*DFactorialRec(n-2)
end
This clearly does not work as it will recursively continue for negative values of n. Please could someone suggest an alteration to stop the memory overflow error?
================================================================
Out of memory. The likely cause is an infinite recursion within the program.
Error in DFactorialRec (line 2)
DFact = n*DFactorialRec(n-2)
================================================================
Thanks!
  댓글 수: 5
Harry Rogers
Harry Rogers 2020년 10월 9일
thank you for the correction however this does not solve the error.. do you have any advice regarding how to make this work?
Walter Roberson
Walter Roberson 2020년 10월 9일
The code I posted worked for me provided that n is a scalar. If it is a non-scalar then you have the problem that your if is comparing a non-scalar to a scalar, and that comparison might be true for some elements but false for others...

댓글을 달려면 로그인하십시오.

채택된 답변

John D'Errico
John D'Errico 2020년 10월 9일
편집: John D'Errico 2020년 10월 9일
Recursive formulas like this always seem useful, but they are terrible in terms of coding, in terms of efficiency. You don't want to write it that way! Yes, the code you wrote looks pretty. That it will not work as you wrote it is a problem of course.
Think about it. For every recursive call, you need to allocate a new workspace, you incur function call overhead. This is a bad thing, and done for absolutely no good reason. Instead, a simple loop is all you need. Start at the bottom.
But better even yet is to not bother with an explicit loop. You can write this function in not much more than one line of code. Just use prod. The rest of what I did was mostly to make it friendly.
function DFact = DFactorial(n)
% Double factorial function, n!!
% https://en.wikipedia.org/wiki/Double_factorial
%
% n!! = 1 for both n == 1 and n == 0.
if isempty(n) || (numel(n) > 1) || (n < 0) || (mod(n,1) ~= 0)
error('The sky is falling. n must be scalar, non-negative, integer.')
end
DFact = 1;
if n > 1
start = 1 + mod(n + 1,2); % caters for either parity of n
DFact = prod(start:2:n);
end
end
Will this code fail for large values of n? Of course. It is easy to overwhelm the dynamic range of a double. But that will happen for any code that uses double precision. An exact integer will not be produced for n > 29 when done in double precision, and inf will result above 300. But again, that will happen in any case.
It is also easy to write a version that handles vector or array arguments for n.
  댓글 수: 2
Harry Rogers
Harry Rogers 2020년 10월 10일
Thats brilliant thank you. You've given me a deeper understanding about different operators that can be used within matlab. I'm faily new to using it so thanks for the advice.
Nate Crummett
Nate Crummett 2022년 8월 7일
Vectorized code from above:
function DFact = DFactorial(n)
% Double factorial function, n!!
% https://en.wikipedia.org/wiki/Double_factorial
%
% n!! = 1 for both n == 1 and n == 0
% Inputs must be vectors of positive, real integers
%
% Designed by John D'Errico on 9 Oct 2020, taken from the MATLAB forum
% Vectorized by Robert Nate Crummett 30 July 2022
DFact = zeros(size(n));
idx_zeros = find(n == 0);
idx_ones = find(n == 1);
DFact([idx_ones, idx_zeros]) = 1;
n_end = n(~DFact);
start = 1 + mod(n_end + 1,2); % caters for either parity of n
prod_results = zeros(size(n_end));
for i = 1:length(n_end)
prod_results(i) = prod(start(i):2:n_end(i));
end
DFact(~DFact) = prod_results;
end

댓글을 달려면 로그인하십시오.

추가 답변 (1개)

SteveC
SteveC 2024년 7월 22일
편집: Walter Roberson 2024년 7월 22일
The double factorial of an integer -1 and larger is defined as in
and generalized in the Pochhammer symbol
It appears in electromagnetic expansions and in special functions.
if the argument is an integer -1 and larger, it is written in Matlab as
fDF = @(bb) prod(bb:(-1):1)
For a vector example
>> arrayfun(fDF,-1:5)
1 1 1 2 6 24 120
If the application manages the validity of the argument, a single line without parity check is OK to define the function.
For big args, a Stirling form...
  댓글 수: 1
SteveC
SteveC 2024년 7월 22일
이동: Voss 2024년 7월 22일
Pardon the typo: (-2) not (-1) in the iterator.
>> fDF = @(bb) prod(bb:(-2):1)
fDF = @(bb)prod(bb:(-2):1)
> arrayfun(fDF,-1:10)
Columns 1 through 7
1 1 1 2 3 8 15
Columns 8 through 12
48 105 384 945 3840
>>

댓글을 달려면 로그인하십시오.

카테고리

Help CenterFile Exchange에서 Argument Definitions에 대해 자세히 알아보기

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by