Code unable to distinguish between perfect and non-perfect numbers in php - php

I am supposed to write a program that:
takes in a positive integer from a html form
then in another php script, checks if this integer is a perfect number or not and print the result (result as in if integer is perfect or not).
A perfect number is a positive integer that is equal to the sum of all its factors EXCLUDING itself.
Problem I'm facing:
The code runs but for every positive number entered, I get the same output which is "Yes, XXX is a perfect number" even when the number isn't.
Could someone help me find the bug(s) in my code? I can't locate the problems in the code.
#html form
<!DOCTYPE html>
<html>
<body>
<form action="lab_2_3.php" method="POST">
Enter positive integer:
<input type="number" name="pos_num" min="1"/>
<input type="submit"/>
</form>
</body>
</html>
#php script
<!DOCTYPE html>
<html>
<body>
<?php
$pos_num = $_POST["pos_num"];
function get_factors($pos_num){
$myarray = array(); //creating new array
for ($i = 1; $i <= ceil(($pos_num ** 0.5)); $i++){
if ($pos_num % $i == 0){
$myarray[] = $pos_num; //appending array in php
}
return $myarray; }
}
function get_total($myarray){
$total_val = 0;
for ($j = 0; $j < count($myarray); $j++){
$total_val += $myarray[$j];
} return $total_val;
}
$a_list = get_factors($pos_num);
$check_if_perf = get_total($a_list);
if ($check_if_perf == $pos_num){
echo "Yes, $pos_num is a perfect number";
}
else{
echo "No, $pos_num is not a perfect number";
}
?>
</body>
</html>

I tried printing out some variables to see what exactly the function was working with:
function get_factors($pos_num){
$myarray = array(); //creating new array
$end = $pos_num ** 0.5;
print "$end\n";
for ($i = 1; $i <= $end; $i++){
print "$i: " . $pos_num % $i . "\n";
if ($pos_num % $i == 0){
$myarray[] = $i; //appending array in php
}
return $myarray; }
}
// ===>
3.1622776601684
1: 0
No, 10 is not a perfect number
From this, it was evident the for loop was not functioning as expected. So step one is to clean up the code and indenting. The error became obvious: misplaced end bracket.
function get_factors($pos_num)
{
$myarray = array(); //creating new array
for ($i = 1; $i <= $pos_num ** 0.5; $i++) {
print "$i: " . $pos_num % $i . "\n";
if ($pos_num % $i == 0){
$myarray[] = $i; //appending array in php
}
}
return $myarray;
}
// ==>
1: 0
2: 0
3: 1
No, 10 is not a perfect number
However, get_factors() does not correctly compute the factorials. The end limit, set by $pos_num ** 0.5 does not gather all the factorials. For example,
print 6 ** 0.5;
// ==>
2.4494897427832
To fix this, we want to get the first half of the factorials (inclusive of n/2)
function get_factors($pos_num)
{
$myarray = array(); //creating new array
for ($i = 1; $i <= $pos_num/2; $i++) {
if ($pos_num % $i == 0){
$myarray[] = $i;
}
}
return $myarray;
}
Now, putting all the code together in a standard format, with notes explaining why (I've also left some of the debugging commented out):
<?php
// testing...
// $_GET["pos_num"] = 496;
// always start out with PHP logic, never HTML.
// Deal with input:
// if submission is not destructive (ie, insert, update, delete), use GET.
// if submission changes data state, use POST. POST should always be followed
// with a redirect. (Post-Redirect-Get pattern)
if(isset($_GET["pos_num"])) {
$pos_num = $_GET["pos_num"];
$a_list = get_factors($pos_num);
$check_if_perf = get_total($a_list);
$is_perfect = ($check_if_perf == $pos_num); // boolean
}
// functional logic:
function get_factors(int $pos_num) : array
{
$myarray = array(); //creating new array
$end = $pos_num /2;
// $end = $pos_num ** 0.5;
// print "$end\n";
for ($i = 1; $i <= $end; $i++){
if ($pos_num % $i == 0){
$myarray[] = $i; //appending array in php
}
}
return $myarray;
}
function get_total(array $myarray) : int
{
$total_val = 0;
for ($j = 0; $j < count($myarray); $j++){
$total_val += $myarray[$j];
}
return $total_val;
}
// print_r(get_factors($pos_num));
// all done with logic, show presentation:
?>
<!DOCTYPE html>
<html>
<body>
<?php if(isset($_GET["pos_num"])): ?>
<div>
<?= $is_perfect
? "Yes, $pos_num is a perfect number"
: "No, $pos_num is not a perfect number"
?>
</div>
<?php endif; ?>
<form action="lab_2_3.php" method="GET">
Enter positive integer:
<input type="number" name="pos_num" min="1"/>
<input type="submit"/>
</form>
</body>
</html>
Working example: http://sandbox.onlinephpfunctions.com/code/d1e5823075c71272c67e09448e6302a4dffead39

Related

Why can't I use a function to simplify my "for loops"

I build a webpage to crack simple MD5 hash of a four digit pin for fun. The method I used was basically try all combination and check against the MD5 value the user has entered. Below is the PHP code I created to accomplish the goal.
Debug Output:
<?php
$answer = "PIN not found";
if (isset($_GET['md5'])) {
$txt = 'abcdefjhig';
$time_pre = microtime(TRUE);
$value = $_GET['md5'];
$show = 15;
for ($i = 0; $i <= 9; $i++) {
$first = $i;
for ($j = 0; $j <= 9; $j++) {
$second = $j;
for ($k = 0; $k <= 9; $k++) {
$third = $k;
for ($x = 0; $x <= 9; $x++) {
$fourth = $x;
$whole = $first . $second . $third . $fourth;
$check = hash('md5', $whole);
if ($check == $value) {
$answer = $whole;
echo "The pin is $answer";
}
if ($show > 0) {
print"$check $whole \n";
$show = $show - 1;
}
}
}
}
}
echo "\n";
$time_post = microtime(TRUE);
print "Elapsed time:";
print $time_post - $time_pre;
}
?>
Notice that in the middle there are four very similar for loops,I tried to simplify this by using functions, but it just returns one four digit number which is 9999 instead of all of them.
Below is the function I created:
function construct($input){
for($i=0; $i<=9, $i++){
$input=$i;
}
return $input
}
Then I tried to call this function for four times to form all of the four digit numbers but it just gives me 9999. Can anybody help? Thanks a lot.
Try this:
for ($i=0; $i<=9999 ; $i++) {
$whole = sprintf('%04d', $i);
$check=hash('md5', $whole);
if($check==$value){
$answer=$whole;
echo "The pin is $answer";
break; //remove this if you do not want to break the loop here
}
if ($show>0) {
print"$check $whole \n";
$show=$show-1;
}
}
You're using numbers from 0 to 9999, so why just loop through those numbers? You can add zero's by using str_pad() like so:
for ($i = 0; $i <= 9999; $i++) {
$whole = str_pad($i, 4, '0', STR_PAD_LEFT);
}
Also I'd like to mention that you really should think about better formatting of your code, especially indentation

PHP - Issue with the printed result

i have this exercise from class, that we need to make script with a function that uses a given string as parameter in lowercase and i have to return that same string in uppercase, i already made that, but when it comes to the printing, it prints the letters in alphabetical order, and i cant figure out whats wrong, here's the code:
<html>
<head>
<title>Ejercicio 10</title>
</head>
<body>
<center><h1>Ejercicio 10 (FunciĆ³n 1)</h1></center>
<h1>
<center>
<form action="ejercicio10.php" method="post">
<input type="text" id="frase" name="frase" placeholders="Introduzca una frase para transformar a mayusculas"/>
<input type="submit" value="Enviar"/>
</form>
<?php
$frase = $_POST['frase'];
function mayusculas($frase) {
$longitud = strlen($frase);
$minusculas = array("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","w","x","y","z"," ");
$mayusculas = array("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","W","X","Y","Z"," ");
$numeroLetras = count($minusculas);
for ($i = 0; $i < $longitud + 1; $i++) {
for ($j=0; $j < $numeroLetras ; $j++) {
$resultado = strrpos($frase, $minusculas[$j], $i);
if($resultado !== FALSE){
print($mayusculas[$j]);
}
}
return null;
}
}
print(mayusculas($frase));
?>
</center>
</h1>
</body>
</html>
Alright for the sake of the exercise, here is what is happening.
You are using two loops. The outer loop iterates as many times as the length of the string, and the inner loop iterates through each letter A through Z.
Here is the correct working version, and then I will explain:
function mayusculas($frase) {
$longitud = strlen($frase);
$minusculas = array("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","w","x","y","z"," ");
$mayusculas = array("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","W","X","Y","Z"," ");
$numeroLetras = count($minusculas);
for ($i = 0; $i < $longitud + 1; $i++) {
for ($j=0; $j < $numeroLetras ; $j++) {
$resultado = strpos($frase, $minusculas[$j], $i);
if($resultado == $i && $resultado !== false) {
print($mayusculas[$j]);
break;
}
}
}
}
Your for loops are correct, it's what you are doing inside them that is not. The following needed to happen:
First, you should use strpos instead of strrpos. We are going through the letters in the word forward, not backwards.
When we check for false in the result, we also need to check that the position it found the letter is the position of the letter we are looking for (i.e. from the outer loop)
Once we find a matching letter at the correct position, you can output it. And then we want to STOP the inner loop iteration since we are done with that loop.
Finally, after the first iteration of the outer loop, you were returning null, which is incorrect. That stops the outer loop from moving on to the second letter. We need to let the looping run its course.
A final note, this is no where close to the best way to do this. I'm only highlighting for learning sake.
Another option if is unnecessary use the function strpos is:
In you PHP section:
$frase = $_POST['frase'];
function mayusculas($frase) {
$longitud = strlen($frase);
$minusculas = array("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","w","x","y","z"," ");
$mayusculas = array("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","W","X","Y","Z"," ");
$numeroLetras = count($minusculas);
for ($i = 0; $i < $longitud; $i++) {
for ($j=0; $j < $numeroLetras ; $j++) {
if($minusculas[$j] == $frase[$i]) {
print($mayusculas[$j]);
}
}
}
}
print(mayusculas($frase));
Using this loop for ($j=0; $j < $numeroLetras ; $j++) { and doing this $resultado = strrpos($frase, $minusculas[$j], $i); means you're basically looping on the $minusculas array only, which is in alphabetical order.
Another error you have in your code is if your string contains repetitive letters like hkgkh, it will only print GKH.
And a major issue you have in your code is the return null statement you have in the for ($i = 0; $i < $longitud + 1; $i++) { loop. This will only fun your loop for 1 iteration.

Fill array with first 100 prime numbers using loop

I have been working on a php function to create an array of prime numbers. So far I have it working to where it lists all the primes from 2 to 1000. What I want to do now is generate the first 100 prime numbers by using the increment count < 100 or something similar. Here is my current code.
<?php
function prima($n)
{
$primeNumbers = []; // Initiate result array
for ($i = 1; $i <= $n; $i++)
{
$counter = 0;
for ($j = 1; $j <= $i; $j++)
{
if ($i % $j == 0)
{
$counter++;
}
}
if ($counter == 2)
{
$primeNumbers[] = $i; // store value to array
}
}
return json_encode($primeNumbers); // return converted json object
}
header('Content-Type: application/json'); // tell browser what to expect
echo prima(1000); // echo the json string returned from function
?>
At the end of the for loop, add 'if (count($primeNumbers) == 100) break;'

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

Create HTML elements in loop

Given a number like i.e: 6 I need to generate 6 DIV elements.
For example:
$number = 6;
// PHP generates the DIV for $number of times (6 in this case).
How can I do it? I am not an expert of PHP loops, if this is the case. Thanks!
Example uses of the different types of loops you could use. Hopefully you can see how they work.
Foreach Loop
$element = "<div></div>";
$count = 6;
foreach( range(1,$count) as $item){
echo $element;
}
While Loop
$element = "<div></div>";
$count = 0;
while($count < 6){
$count++;
echo $element;
}
Simple For Loop
$element = "<div></div>";
$count = 6;
for ($i = 0; $i < $count; $i++) {
echo $element;
}
function generateDIVs($number)
{
for ($i = 0; $i <= $number; $i++)
{
echo "<div><div/>";
}
}
In order to generate 6 div elements loop is necessary.
using while loop:
$count = 1;
while($count <= 6){
$count++;
echo "<div></div>";
}
using for loop:
$count = 6;
for ($i = 0; $i < $count; $i++) {
echo "<div></div>";
}
for ($i = 0; $i < 6; $i++) {
echo "<div class=\"example\"></div>";
}
Note that IDs (the # part) have to be unique on a page, so you can't have 6 different divs with the same #example id.
http://php.net/manual/en/control-structures.for.php
Here are some examples I use often, for quick mock-upping repeated HTML while working with PHP
array_walk() with iteration index and range
$range = range(0, 5);
array_walk($range, function($i) {
echo "
<section class='fooBar'>
The $i content
</section>
";
});
If tired of escaping double quotes \" or using ' or concatenation hell, you could simply use Heredoc.
$html = function($i) {
echo <<<EOT
<section class="fooBar">
The $i content
</section>
EOT;
};
array_map($html, range(1, 6));
The only small "disadvantage" of using Heredoc is that the closing EOT; cannot have leading and following spaces or tabs - which might look ugly in a well structured markup, so I often place my functions on top of the document, and use <?php array_map($html, range(0, 5)) ?> where needed.
str_repeat() when an index is not needed
$html = "
<section class='fooBar'>
Some content
</section>
";
echo str_repeat($html, 6);
you need echo command. Basically you are generating html by printing a string. Example
echo '<div> </div>';
will generate 1 div. You need it 6 times. You might want to use loop as well, but this is too basic question and I gave you a start.

Categories