Project Euler #3 - Getting weird fatal error - php

I'm working on Project Euler problem 3, but my code gives a weird error. The error is:
Fatal error: Can't use function return value in write context in
D:\Google Drive\ITvitae\PHP5\ProjectEuler\PE3-PrimeFactor2.php on line
52
This is the code I'm running:
<html>
<body>
<?php
ini_set('memory_limit', '1024M');
ini_set('set_time_limit', '120');
$max = 1000000;
#$max = 600851475143;
$primes = array();
// Define sqrt ceiling
$maxSqrt = ceil(sqrt($max));
function isPrime($num) {
// 1 is not prime
if ($num == 1)
return false;
// 2 is prime
if ($num == 2)
return true;
// Removes all even numbers
if ($num % 2 == 0) {
return false;
}
// Check odd numbers, if factor return false
// The sqrt can be an aproximation, round it to the next highest integer value.
$ceil = ceil(sqrt($num));
for ($i = 3; $i <= $ceil; $i = $i + 2) {
if($num % $i == 0)
return false;
}
return true;
}
//Push latest prime into array
for ($i = 2; $i <= $maxSqrt; $i++) {
if (isPrime($i)) {
array_push($primes, $i);
}
}
// Check whether $max is divisible by $primes($j)
for ($j = 0; $j <= count($primes); $j++) {
if ($max % $primes($j) = 0) {
$max = $max / $primes($j);
}
}
//echo "<pre>";
//var_dump($primes);
//echo "</pre>";
echo array_pop($primes);
?>
</body>
</html>
Line 52 being
if ($max % $primes($j) = 0) {
Under // Check whether $max is divisible by $primes($j)
I've never seen this error before, and I don't understand why it's giving it. In my head, the logic is flawless (which inevitably, therefore it isn't). What is going wrong here?
EDIT: Changed it to
if ($max % $primes($j) == 0) {
But it tells me the Function name must be a string. I don't understand.

The first problem was, you used = for comparison. = is an assignment and you couldn't assign a value to an expression (that wouldn't have a usefull meaning..)
Second, you have to use [] for array access, instead of (). Using () after an identifier or var always tries to call an function. In your case $primes is an array, which isn't a function.
Third, you should fix the of-by-one array access error in your for-loop.
for ($j = 0; $j < count($primes); $j++) { // < instead of <=
if ($max % $primes[$j] == 0) { // == instead of = and [] instead of ()
$max = $max / $primes[$j]; // again [] instead of ()
}
}

Related

PHP - check if number is prime

I'm trying to create a function which checks whether the number is prime or not. BUT I want this function to echo to the user 'prime' or 'NOT prime' - and that's where my problem starts.
Let me show you my code:
class IsPrime
{
function check($num)
{
for ($i = 2; $i < $num; $i++)
{
if ($num % $i == 0)
{
echo 'NOT prime';
break;
}
}
echo 'Prime';
}
}
$x = new IsPrime();
$x->check(4);
The problem is that when I put any prime number - it works correctly, but when I put any not prime number - it also echos second echo, sth like this: 'NOT prime prime'.
How can I make it echo only the right answer ?
in 54 59 bytes:
function is_prime($n){for($i=$n;--$i&&$n%$i;);return$i==1;}
loops $i down from $n-1 until it finds a divisor of $n; $n is prime if that divisor is 1.
add 10 bytes for much better performance:
function is_prime($n){for($i=$n**.5|1;$i&&$n%$i--;);return!$i&&$n>1;}
loops $i from (approx.) sqrt($n) to 1 looking for a divisor with a post-decrement on $i.
If the divisor is 1, $i will be 0 at the end, and !$i gives true.
This solition uses a trick: For $n=2 or 3, $i will be initialized to 1 → loop exits in first iteration. For larger even square roots ($n**.5|0), |1 serves as +1. For odd square roots, +1 is not needed because: if $n is divisible by root+1, it is also divisible by 2. Unfortunately, this can cost a lot of iterations; so you better
add another 7 bytes for even better performance:
function is_prime($n){for($i=~-$n**.5|0;$i&&$n%$i--;);return!$i&$n>2|$n==2;}
$n=2 needs a special case here: inital $i=2 divides $n=2 → final $i=1 → returns false.
Adding 1 to $n instead of the square root is enough to avoid failures; but:
I did not count the iterations but only tested time consumption; and that only in TiO instead of a controlled environment. The difference between the last two versions was smaller than the deviation between several runs.
Significant test results may be added later.
This could be a long procedure if the number is really a prime number. There is a shorter procedure as well.
We need not run the for loop upto the number itself. Instead, we can run it upto the Highest Integer less than or equal to the square root of the number.
class IsPrime
{
function check($num)
{
$bCheck = True;
$highestIntegralSquareRoot = floor(sqrt($num));
for ($i = 2; $i <= $highestIntegralSquareRoot; $i++)
{
if ($num % $i == 0)
{
$bCheck = False;
break;
}
}
if $bCheck
echo 'Prime';
else
echo 'NOT prime';
}
}
$x = new IsPrime();
$x->check(97);
Now, in the above, if we check check whether 97 is prime or not (actually, it is), then the loop need not run from 2 to 97, but only from 2 to 9. (Square root of 97 is 9.8488578018, and highest integer less than or equal to that is 9. Similarly, we can check for number 121 (this is not a prime number, as it is divisible by 11). The limit will be increased from 2 to 11 in a similar matter. And so on.
Actually, we need to check the divisibility of the number by the smaller prime numbers in the vicinity, but that would be more complex.
Hope this helps.
As many answer pointed out, your logic code has a problem: when you get i such that num % i == 0, you print "NOT prime" and quit the loop, after that, you still print "Prime". Some guys moved echo "Prime" in if-else, it is still wrong. One way to approach, for example,
class IsPrime
{
function check($num)
{
$bCheck = True;
for ($i = 2; $i < $num; $i++)
{
if ($num % $i == 0)
{
$bCheck = False;
break;
}
}
if $bCheck
echo 'Prime';
else
echo 'NOT prime';
}
}
$x = new IsPrime();
$x->check(4);
<?php
function primeCheck($num)
{
if ($num == 1)
return false;
for ($i = 2; $i <= $num/2; $i++)
{
if ($num % $i == 0)
{
return false;
}
}
return true;
}
$primeNumber = primeCheck(17);
if ($primeNumber == true)
{
echo "Is Prime";
}
else
{
echo "Is Not Prime";
}
?>
The break is only breaking the for loop,
use return; instead. it will exit the function
Just use return:
class IsPrime
{
function check($num)
{
for ($i = 2; $i < $num; $i++)
{
if ($num % $i == 0)
{
echo 'NOT prime';
return; // that you need
}
}
echo 'Prime';
}
}
$x = new IsPrime();
$x->check(4);
if/else notation
return notation
You can find prime numbers and non prime numbers from 1 to your limit and its count.
public function prime_checker($count){
$counter=0;
$no_prime=0;
for($i=2 ; $i<=$count; $i++ ){
for($j=2 ; $j<$i ; $j++ ){
if($i % $j == 0){
echo $i.'is not prime<br/>';
$no_prime=$i;
break;
}
}
if($i != $no_prime){
$prime_numbers[$counter]=$i;
$counter=$counter+1;
}
}
echo '<br/>'.$counter.'prime numbers<br/><br/>';
for($i=0 ; $i<$counter ; $i++ ){
echo $prime_numbers[$i].' is prime<br/>';
}
}
You can check number is prime or not & without using loop with this function:
function is_prime($p) {
$r1 = $p%2;
$r2 = $p%3;
$r3 = $p%5;
return ($p > 1) && (($r1 >= 1) && ($r2 >= 1) && ($r3 >= 1)) || in_array($p, [2,3,5]);
}
Please Check this
class IsPrime
{
function check($num)
{
for ($i = 2; $i < $num; $i++)
{
if ($num % $i == 0)
{
return 'NOT prime';
}
}
return 'Prime';
}
}
$x = new IsPrime();
$result = $x->check(4);
echo $result;
try this
class IsPrime
{
function check($num)
{
for ($i = 2; $i < $num; $i++)
{
if ($num % $i == 0)
{
echo 'NOT prime';
break;
}
else
{
echo 'Prime';
}
}
//echo 'Prime';
}
}
$x = new IsPrime();
$x->check(3);
Put else part otherwise it will always return Prime
for ($i = 2; $i < $num; $i++)
{
if ($num % $i == 0)
{
echo 'NOT prime';
break;
}
echo 'Prime';
}
You can print "Prime" as a return to the function to ensure nothing is printed during the function except for the condition for "NOT prime".
class IsPrime
{
function check($num)
{
for ($i = 2; $i < $num; $i++)
{
if ($num % $i == 0)
{
echo 'NOT prime';
break;
}
}
return "Prime";
}
}
$x = new IsPrime();
echo $x->check(4);
$num = ceil(sqrt($num));
$is_prime = true;
for($j=3; $j<=$num; $j=$j+2){
if($i%$j == 0){
$is_prime = false;
break;
}
}
if($is_prime){
echo "No is Prime";
}
Note: Start loop from 2 as it is the only even prime no. Increment with 2 as no even no is a prime no.
=> Code for finding all prime no in range (2-100)
$limit = 100; $arr = array(2);
for($i=3; $i<=$limit; $i=$i+2){
$num = ceil(sqrt($i));
$is_prime = true;
for($j=3; $j<=$num; $j=$j+2){
if($i%$j == 0){
$is_prime = false;
break;
}
}
if($is_prime){
$arr[] = $i;
}
}
I made a similar one where a user types in a number and PHP checks if the number is prime or not.
HTML
<p>See if your number is a prime number</p>
<form>
<input type='number' name='number'>
<input type='submit' value='Check!'>
</form>
PHP
if ($_GET) {
$i = 2;
$isPrime = true;
while ($i < $_GET['number']) {
if ($_GET['number'] % $i == 0){
// Number is NOT prime
$isPrime = false;
}
$i++;
}
if ($isPrime){
echo '<p>'.$i.' is a prime number!';
} else {
echo '<p>'.$i.' is NOT a prime number';
}
}
Hopefully this works for you.
First, don't make a mistake here:
for ($i = 2; $i < $num; $i++)
and then:
if ($num % $i == 0) return false;
2 % 2 equals 0 and then 2 will result as NOT prime.
Next, you don't have to check even numbers, so after you check if $num == 2, better performance is:
for ($i = 3; $i < $num/2; $i += 2)
Notice $num/2 - you don't have to check beyond that point.
And even better is:
for ($i = 3; $i*$i <= $num; $i += 2)
This is because when you check for division with 2 and 3 all other NON prime numbers are product of two (or more) prime numbers (e.g. 49 = 7*7 or 55 = 5*11). In the worst case scenario your $i pointer would reach a square root of $num (like in 49 = 7*7). That's why you check until $i*$i <= $num.
PHP 4
You can do enough random checks ($i=20) to bring the false positive probability very low.
/*
The Rabin/Miller Algorithm.
*/
function is_prime($n, $i = 10)
{
if (($n == 1) == ($n & 1)) return $n == 2;
if ($n < 51529) // will not be repeated 7 times (deletable condition)
return ($n & 1) & (($n < 6) * 42 + 0x208A2882) >> $n % 30 && ($n < 49 || ($n % 7 && $n % 11 && $n % 13 && $n % 17 && $n % 19 && $n % 23 && $n % 29 && $n % 31 && $n % 37 && ($n < 1369 || ($n % 41 && $n % 43 && $n % 47 && $n % 53 && $n % 59 && $n % 61 && $n % 67 && $n % 71 && $n % 73 && ( $n < 6241 || ($n % 79 && $n % 83 && $n % 89 && $n % 97 && $n % 101 && $n % 103 && $n % 107 && $n % 109 && $n % 113 && ( $n < 16129 || ($n % 127 && $n % 131 && $n % 137 && $n % 139 && $n % 149 && $n % 151 && $n % 157 && $n % 163 && $n % 167 && ( $n < 29929 || ($n % 173 && $n % 179 && $n % 181 && $n % 191 && $n % 193 && $n % 197 && $n % 199 && $n % 211 && $n % 223))))))))));
for ($a = $c = $n - 1, $d = $c - 1, $b = 0; !($a & 1); $a >>= 1, ++$b) ;
for (; $i--;) {
do for ($e = $f = mt_rand(1, $d), $g = $n; ($e %= $g) && ($g %= $e);) ;
while ($e > 1 && $g > 1);
for ($e = $g = 1; $g <= $a; $g <<= 1) ;
for (; $g >>= 1; $e = ($e * $e) % $n, $g & $a && ($e = ($f * $e) % $n)) ;
if ($e == 1) continue;
for ($r = $b; $r-- ; $e = ($e * $e) % $n)
if ($e == $c) continue 2;
return 0;
}
return 1;
}
echo is_prime(2147483647); // 1
echo is_prime(PHP_MAJOR_VERSION); // You Know
This PHP4 variant of the Fermat test has a polynomial runtime in log($n).
Just use it for small numbers, when $n < 2147483647, otherwise it's gmp_prob_prime.
Thank You.
function is_prime($number)
{
return (bool) !preg_match('/^1?$|^(11+?)\1+$/x', str_repeat('1', $number));
}
Entire program is correct . But only you should do replace break with exit function .because break only used to exit loop which are enclosed with curly braces {} and exit are used to stop the execution of an entire script.
class IsPrime
{
function check($num)
{
for ($i = 2; $i < $num; $i++)
{
if ($num % $i == 0)
{
echo 'NOT prime';
break;
}
}
echo 'Prime';
}
}
$x = new IsPrime();
$x->check(4);
That is my solution. If you put the condition in the loop and break after it, it's never going to finish with the check.
$num = rand ( 1, 1000 );
$notPri = null;
for($check = 2; $check < $num; $check ++) {
if ($num % $check == 0) {
$notPri ++;
}
}
if ($neEpri == 0) {
echo $num . "<br>Prime!";
} else {
echo $num . "<br>Not a prime!";
}

Is Generator supposed to be lazy?

I tried to calculate the nth prime number in PHP:
function is_prime($n) {
if ($n <= 1) {
return false;
} elseif ($n <= 3) {
return true;
} elseif (($n % 2 == 0) || ($n % 3 == 0)) {
return false;
}
$i = 5;
while ($i * $i <= $n) {
if (($n % $i == 0) || ($n % ($i + 2) == 0)) {
return false;
$i = $i + 6;
}
}
return true;
}
function prime_gen() {
for($x=0; $x< PHP_INT_MAX; $x++) {
if(is_prime($x)){
yield $x;
}
}
}
function nth_prime($n) {
for($i=0; $i<=$n; $i++) {
$ps = iterator_to_array(prime_gen());
}
return $ps[$n-1];
}
echo nth_prime(9);
I got Maximum execution time of 3 seconds exceeded error. Is generator supposed to be lazy? Shouldn't I write for($x=0; $x< PHP_INT_MAX; $x++)?
iterator_to_array iterates the entire generator until it is exhausted and gives you the result in an array. The generator is "lazy", but you're explicitly breaking that and are forcing the evaluation of the entire generator. Moreover, you're doing that in a loop. You pretty much just need to get rid of iterator_to_array. Better solution:
$nth = 0;
foreach (prime_gen() as $prime) {
if (++$nth >= $n) {
break;
}
}
return $prime;

I dont know what to do with this PHP Code

The code below basically helps in finding out if a number is a Palindromic Number or not. Although I get my execution done with the output, I just can seem to handle all the "screams" and fatal errors that I get. How do I handle this. Just a beginner and trust you can explain in a way that I may be able to understand..
<?php
for ($num = 1; $num <= 20; ++$num){
$_array1 = str_split($num);
//print_r($_array1);
//echo "<br/>";
$_array2 = array_reverse($_array1);
//print_r($_array2);
//echo "<br/>";
$i = 0;
$j = 0;
while ($i < sizeof($_array1) && $j < sizeof($_array2)){
if ($_array1[$i] == $_array2[$j]){
++$i;
++$j;
}
}
if ($_array1[$i] == $_array2[$j]){
echo "The number $num is a Palindrome Number";
}
}
?>
You get to the size of elements, which is 1. However, if your array has only one element, which is the case for 1-digit numbers, then sizeof($_array) === 1. Which means that the biggest possible index you can use is 0. You need to change your code to something like this:
<?php
for ($num = 1; $num <= 20; ++$num){
$_array1 = str_split($num);
//print_r($_array1);
//echo "<br/>";
$_array2 = array_reverse($_array1);
//print_r($_array2);
//echo "<br/>";
$i = 0;
$j = 0;
$different = false;
while ((!$different) && ($i < sizeof($_array1))){
if ($_array1[$i] == $_array2[$j]){
++$i;
++$j;
} else {
$different = true;
}
}
if (!$different){
echo "The number $num is a Palindrome Number";
}
}
?>
But you are inversing the array without a need to do so and you are looping for unnecessarily long. I propose this function to determine whether an array is a palindrome:
function isPalindrome($input) {
$size = count($input);
for ($index = 0; $index < $size / 2; $index++) {
if ($input[$index] != $input[$size - $index - 1]) {
return false;
}
}
return true;
}
Note, that:
the function assumes that the keys of the array are numbers
the function uses a single array
the size of the array is stored into a local variable to not calculate it repeatedly
the cycle cycles until half of the array, since going beyond that is unnecessary, due to the symmetrical nature of the != operator
the function returns false when the first difference is found, to further optimize the checking
if there were no differences, the function returns true, representing that the input is a palindrome

Solving Algorithm (Josephus permutation) in PHP

Suppose 100 people line up in a circle. Counting from person 1 to person 14, remove person from the circle. Following the count order, counting again and remove the 14th person. Repeat. Who is the last person standing?
I've tried everything to solve this and it seems to not be working with dead loops.
<?php
//init array
$array = array();
for ($i = 0; $i < 100; $i++) { $array[] = $i; }
//start from 0
$pos = 0;
while (count_not_null($array) > 1) {
//reset count
$count = 0;
while (true) {
//ignore NULL for count, that position is already removed
if ($array[$pos] !== NULL) {
$count++;
if($count == 14) { break; }
}
$pos++;
//go back to beginning, we cant go over 0-99, for 100 elements
if ($pos > 99) { $pos = 0; }
}
echo "set index {$pos} to NULL!" ."<br>";
$array[$pos] = NULL;
if (count_not_null($array) === 1) { break; }
}
echo "<pre>";
print_r($array);
echo "</pre>";
//counting not null elements
function count_not_null($array) {
$count = 0;
for ($i = 0; $i < count($array); $i++) {
if ($array[$i] !== NULL) { $count++; }
}
return $count;
}
?>
For solving this with as little code as possible and quickest you could do like this:
function josephus($n,$k){
if($n ==1)
return 1;
else
return (josephus($n-1,$k)+$k-1) % $n+1;
}
echo josephus(100,14);
Here we are using an recursive statement instead, as what you are trying to solve can be defined by this mathematical statement f(n,k) = (f(n-1,k) + k) % n
For reading more about this mathematical formula you can see it here on the wiki page.
The problem is this while loop
while ($count < 14) {
if ($array[$pos] != NULL) {
$count++;
}
$pos++;
if ($pos > 99) { $pos = 0; }
}
Because you increment $pos even if count is 14 you will end with incorrect values and loop forever. Replace it with this:
while (true) {
if ($array[$pos] != NULL) {
$count++;
if($count == 14) {break;}
}
$pos++;
if ($pos > 99) { $pos = 0; }
}
Also comparing 0 to NULL won't give you the expected results as mentioned by #Barmar, so you can either change the NULL comparison, or start counting from 1
NOTE: This would be way faster if you didn't loop through array every time :D consider using a variable to count the remaining items
Anyone who stumbles across this again, here is a slightly quicker one:
function josephus($n){
$toBin = decbin($n); // to binary
$toBack = substr($toBin,1) . "1"; // remove first bit and add to end
return bindec($toBack); // back to value
}
Based on this solution.

I need to find all amicable numbers up to a certain number

Here is my code:
$n = 300;
$set = 0;
$set2 = 0;
for($i = 1; $i<$n; $i++)
{
for($j = 1; $j <$i; $j++)
{
$qol = $i % $j;
if($qol == 0)
{
$set += $j;
}
}
for($s=1; $s<$set; $s++)
{
$qol2 = $set % $s;
if($s == 0)
{
$set2 += $s;
}
}
if($set2 == $i)
{
echo "$set and $i are amicable numbers</br>";
}
}
I do not know what the heck the problem is!
FYI: 220 and 284 are an example of amicable numbers. The sum of the proper divisors of one number are equal to other number and vice versa (wiki).
I am having troubles following your logic. In your code how would $set2 == $i ever be true? Seems to me that $i would always be greater.
I would do it the following way:
First make a separate function that finds the sums of the proper divisors:
// Function to output sum of proper divisors of $num
function sumDiv($num) {
// Return 0 if $num is 1 or less
if ($num <= 1) {
return 0;
}
$result = 1; // All nums divide by 1
$sqrt = sqrt($num);
// Add divisors to result
for ($i = 2; $i < $sqrt; $i++) {
if ($num % $i == 0) {
$result += $i + $num / $i;
}
}
// If perfect square add squareroot to result
if (floor($sqrt) == $sqrt) {
$result += $sqrt;
}
return $result;
}
Next check each iteration for a match:
$n = 1500;
for ($i = 1; $i < $n; $i++) {
// Get sum of proper devisors of $i, and sum of div. of result.
$currentDivs = sumDiv($i);
$resultDivs = sumDiv($currentDivs);
// Check for a match with sums not equal to each other.
if ($i == $resultDivs && $currentDivs != $resultDivs) {
echo "$i and $currentDivs are amicable numbers<br>";
}
}
Here a functioning phpfiddle.
Warning: Large numbers will take very long to process!

Categories