Jump to content
Saggi

Get Factorial

Recommended Posts

Hello all, Noob here 😑. Need help in solving this task.  

I Wrote a function which returns a factorial number but how to pass the logic that the passing parameter must be an integer. Also, if any other data type is passed, function should return error “Please provide correct data type”. 

Many thanks, 
 

function fact ($x) {  
    if($x <= 1) {  
        return 1;  
    } else  {  
        return $x * fact($x - 1);  
    }  
}  
echo fact(3);    

 

Share this post


Link to post
Share on other sites

ctype_digit()

function fact ($x) {
    if (!ctype_digit("$x") ) {                             // CAVEAT: cast $x to string type
        return 'Please provide an integer';
    }  
    if($x <= 1) {  
        return 1;  
    } else  {  
        return $x * fact($x - 1);  
    }  
}  

 

Edited by Barand
caveat
  • Like 1

Share this post


Link to post
Share on other sites

Minor point. I think the check will catch negative integers since it is cast to a string but the error should say 'Please provide a positive integer".

Share this post


Link to post
Share on other sites

FWIW, what the task to specifically create a recursive function? If not, you can get a factorial much simpler (of course you'd still want the integer check

array_product(range(1, $number));

 

Share this post


Link to post
Share on other sites

Hi @Barand,

I am wondering why you would be introducing strings when this is specifically about int's. IMO is_int should be used instead of ctype_digit.

OP, the else is redundant. You can remove it. Additionally, IMO the int check should not be in the function. The function/method should do one thing and do it well.

As is example
 

function fact($x)
{
    if (!is_int($x)) {
        return 'Please provide an integer';
    }
    if ($x <= 1) {
        return 1;
    }
    return $x * fact($x - 1);
}

echo fact(5);

Suggested Example

function fact(int $x): int
{
    return $x <= 1 ? 1 : $x * fact($x - 1);
}

$x = 5;
echo is_int($x) ? fact($x) : 'Please provide an integer';

 

 

 

 

Edited by benanamen

Share this post


Link to post
Share on other sites
1 hour ago, benanamen said:

I am wondering why you would be introducing strings when this is specifically about int's. IMO is_int should be used instead of ctype_digit.

The OP never stated "where" the value is coming from. If the value is coming from a POST/GET variable it will ALWAYS be a string and always fail the is_int() test - even if the value is something like "5". If the value is specifically cast as an integer then there would be no reason to even test if it is an integer to begin with. So, it would only make sense to test if the value "looks" like an integer when it is an unknown string value that can be a string representation of an integer or some other invalid value. @Barand's test makes more sense.

Share this post


Link to post
Share on other sites
2 hours ago, Psycho said:

The OP never stated "where" the value is coming from.

Which is why you cant say "@Barand's test makes more sense." Based on OP's code, he expects there could be a negative int, otherwise he wouldn't be checking for it.

If "int" is negative, @Barands solution will fail (false).

var_dump(ctype_digit('-128')); // False

Casting the string to an int wouldn't work either.

$x =  (int) '5';

Yes , it will make it an int and support negative values, but it will cast "anything" you put in there into an int such as the following and then you cannot check if it is a real int.

$x =  (int) 'xx'; // int 0

 

So what to do then? One option that also addresses the source as a string argument would be the following.

function fact($x): int
{
    return $x <= 1 ? 1 : $x * fact($x - 1);
}

$x = '-2147483648';// OK
$x = -2147483648;// OK 
$x = 5; // OK
$x = '5';// OK
$x = 'ABC'; // Fail: Please provide an integer                   
echo (filter_var($x, FILTER_VALIDATE_INT) === 0 || filter_var($x, FILTER_VALIDATE_INT)) ? fact($x) : 'Please provide an integer';

 

 

Edited by benanamen

Share this post


Link to post
Share on other sites
On 12/20/2019 at 3:37 PM, benanamen said:

Which is why you cant say "@Barand's test makes more sense." Based on OP's code, he expects there could be a negative int, otherwise he wouldn't be checking for it.

If "int" is negative, @Barands solution will fail (false).

If the value is a negative integer - it should fail. Factorials of negative numbers is not possible (e.g. division by zero) - unless you want to get into abstract complex numbers which would require the use of the gamma function. 

The only valid values for a factorial are positive integers from zero to ∞. The only exception I can think of to the ctype_digit() test would be if you wanted to allow a plus symbol; in which case you would still need to remove it during the computation.

Share this post


Link to post
Share on other sites
1 hour ago, Psycho said:

Factorials of negative numbers is not possible

Thanks @Psycho. Shows how much I knew about Factorials, lol. :shrug:

Share this post


Link to post
Share on other sites
On 12/20/2019 at 9:37 PM, benanamen said:

Based on OP's code, he expects there could be a negative int, otherwise he wouldn't be checking for it.

He's testing for 0 or 1.

0! and 1! both equate to 1, so no need to calculate any further.

Every recursive function needs a stop condition otherwise you quickly overflow the stack with an infinite recursion.

  • Like 1

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.