Im trying to get out an average value from a vote function.
<?php
$file = file("textfile.txt");
$textfil = file_get_contents("textfile.txt");
$textfill = str_split($textfil);
echo "Number of votes: " . count($textfill) . "<br>";
$sum = 0;
foreach ($textfill as $vote) {
$sum = $sum + intval($vote);
}
echo "Average: " . $sum;
?>
Simple by substitute (+) with a (/), and even tried a (%). But still getting error message.
Would appreciate alot if anyone could help me out and tell me what im doing wrong.
/thanks
Edit
Sidenote: Please read an explanation under "First answer given" further down below.
This version will take into account any blank lines in a file, if the content looks like:
1
2
3
// <- blank line
Sidenote: Please provide a sample of your text file. A comment has already been given to that effect.
PHP
<?php
// first line not required
// $file = file("textfile.txt");
$textfil = file_get_contents("textfile.txt");
$textfill = array_filter(array_map("trim", file("textfile.txt")), "strlen");
echo "Number of votes: " . count($textfill) . "<br>";
$sum = 0;
foreach ($textfill as $vote) {
$sum += intval($vote);
}
$avg = $sum / count($textfill);
echo "Average: " . $avg;
?>
First answer given
Using the following in a text file: (since no example of file content was given)
5
5
5
IMPORTANT NOTE: There should not be a carriage return after the last entry.
produced
Number of votes: 5
Average: 3
which is false, since there are 3 entries in the text file.
explode() should be used, and not str_split()
The following using the same text file produced:
Number of votes: 3
Average: 5
which is correct. In simple mathematics, averages are done by adding all numbers then dividing them by how many numbers there are.
In this case it's 3 numbers (all 5's) added equals 15, divided by 3 is 5.
Sidenote: The first line is not required $file = file("textfile2.txt");
<?php
// first line not required
// $file = file("textfile.txt");
$textfil = file_get_contents("textfile.txt");
$textfill = explode("\n", $textfil);
echo "Number of votes: " . count($textfill) . "<br>";
$sum = 0;
foreach ($textfill as $vote) {
$sum += intval($vote);
}
$avg = $sum / count($textfill);
echo "Average: " . $avg;
?>
Footnotes:
If the average comes out to 8.33333 and you would like it to be rounded off to 8, use:
echo "Average: " . floor($avg);
If the average comes out to 8.33333 and would like it to be as 9 you would use:
echo "Average: " . ceil($avg);
ceil() function
floor() function
You may be mixing in stuff that can't be divided, like text, etc. I don't know what your text file looks like. intval may be having a problem with arrays. You may try:
foreach ($textfill as $vote) {
if(is_int($vote) {
$sum += $vote;
}
}
echo "Average: " . $sum;
Lower school math says:
foreach ($textfill as $vote) {
$sum += intval($vote);
}
$avg = $sum / count($textfill);
The average value is calculated by divide the sum with the number of votes. This line will print the average value:
echo "Average: " . $sum/count($textfill);
Related
(Working on a search algorithm) I want to iterate over possible matches with two bits set in a 16bit word. Seems like a silly problem with a currently overly-complex solution.
Iteration should return (decimal) 3,5,6,9,10,12,17...
What's the proper word for the problem? Bit-mask-looping?
Any clever function for this?
Current code - now updated:
(As it stands, i guess there's no easier way around this.)
<?php
function biterate($numBits=8, $setBits=2, $maxval=null) {
//init
if(is_null($maxval)) $maxval = (pow(2,$setBits)-1) * pow(2,$numBits - $setBits);
$err = 0;
header('content-type:text/plain');
echo '-- ' . $setBits . ' of ' . $numBits . " --\r\n";
$result = str_pad('', $numBits - $setBits, '0') . str_pad('', $setBits, '1');
do {
$err++;
if($err > 200) die('bad code');
//echo and calc next val.
echo $result . ' : ' . bindec($result) . "\r\n";
//count set bits and search for '01' to be replaced with '10'. From LSB.
$bitDivend = '';
$hit = false;
for($i=$numBits;$i>0;$i--) {
if(substr($result,$i-2,2) == '01') {
$hit = true;
//do the replacement and replace the lower part with bitDivend.
$result = substr($result, 0, $i-2) . '10';
$result .= str_pad('',$numBits - $i - strlen($bitDivend),'0');
$result .= $bitDivend;
//exit loop
$i = 0;
}
if($result[$i-1] == '1') $bitDivend .= '1';
}
} while($hit && bindec($result) <= $maxval);
}
biterate(8,2);
biterate(8,7);
biterate();
If you just want all the 16 bit ints with 2 bits set, the following code should do it:
<?php
for($i=1;$i<16;$i++)
{
for($j=0;$j<$i;$j++)
{
echo (1<<$i)|(1<<$j) , "\r\n";
}
}
?>
If you look at the bit patterns of the numbers you can see how it works:
11 3
101 5
110 6
1001 9
1010 10
1100 12
10001 17
10010 18
10100 20
11000 24
etc. You just move the most significant bit one place to the left (another power of 2) for each iteration of the outer loop, and inside the inner loop you iterate from the least significant bit (1) to 1 place to the right of the most significant bit.
If you wanted to generalise this to support an arbitrary number of bits and places, you could extend the above algorithm using recursion:
<?php
function biterate_recursive($numBits=8, $setBits=2, $initialValue=0, $maxval=null) {
for($i=$setBits-1;$i<$numBits;$i++)
{
if(!is_null($maxval) && ($initialValue|(1<<$i)) > $maxval)
break;
if($setBits==1)
echo $initialValue|(1<<$i) , "\r\n";
else
biterate_recursive($i, $setBits-1, $initialValue|(1<<$i), $maxval);
}
}
biterate_recursive(16, 2);
?>
You can also think of the problem as just choosing combinations i.e. C(16,2) choosing 2 numbers a,b from the set 0-15, and then calculating (1<<a)|(1<<b). However you have to be careful about your choice of combination algorithm if you want to get the numbers in order.
I'm trying to divide in PHP, but I don't get the correct answer when I echo it out.
<?php
$names = file('rating.txt');
// To check the number of lines
echo "In the textfile: " . count($names).'<br>';
$sum = 0;
foreach($names as $name)
{
$sum = $sum + $name;
}
echo "Total sum: " . $sum;
?>
I tried:
($sum/$name)
But that gives me the wrong result. If I try:
($sum/$names)
I get the following error message:
Fatal error: Unsupported operand types in C:\xampp\htdocs\lab5\rating\index.php on line 55
How do I get the $sum divided by the number of lines I have in the text file?
Change $sum = $sum + $name; to $sum .= intval($name);. intval converts the string into a number.
If this does not work, the problem is with rating.txt, which you are not showing. ($sum/$names) won't work because you can only divide a number by a another number (Which should be non-zero).
I have written a little script to automate some calculations for me. It is pretty simple.
1*3=3
2*3=6
3*3=9 and so on. When the answer(product) is more than one digit long I want it to add the digits of the answer.
3*4=12 || 1+2=3.
I want it to automatically add the answer if it is more than one digit no matter how many times adding the answer arrives larger than a single digit.
as in when you reach 13*3=39 || 3+9=12 || 1+2=3
Currently my code does not loop, and i cannot figure out how to make it loop here.
http://screencast.com/t/MdpQ9XEz
Also, it is not adding up more than 2 digit answers see 34*3=102. any help here to allow it infinity addition would be great.
As each line is produced the answers get larger, so it should add as many digits there are in the answer.
here is my code:
$i = 1; //Start with one
function count_digit($number) {
return strlen((string) $number);
};
while($i < 500){
$product = $i * 3; //Multiply set
$number_of_digits = count_digit($product); //calls function to count digits of $sum
if($number_of_digits > 1){ //if $sum has more than one digit add the digits together
$addproduct = strval($product);//seperates the digits of $sum
$ii = 0;
while($ii <= $number_of_digits -1){
$io = $ii + 1;
if($io < $number_of_digits){
$one = intval($addproduct[$ii]);
$two = intval($addproduct[$io]);
$sum = $one + $two;
print($i . ' * 3 = ' .$product. ' || ' .$one. ' + ' .$two. ' = ' .$sum. '<br>');
};$ii++;
};
}else{
Print ($i . ' * 3 = ' .$product.'<br>'); //Print Set
};
$i++; //add one
}
For a start, you might replace the $i=1, while ..., and $i++ into one statement: for ($i=0; $i<500; $i++) {.... - see http://nz1.php.net/manual/en/control-structures.for.php for more information about for loops. It comes out to effectively the same code, but keeps the three parts (initialisation, test, increment counter) together; it makes it clear that they are related, and quicker to understand.
Next I would replace conversion of the number to a string, seeing if the length of the string is greater than one, etc.... with:
while ($product>10) {
$out=0;
while ($product) {
$out+=$product%10;
$product=(integer)($product/10);
}
$product=$out;
}
Note that at no time am I treating a number as a string - I avoid that wherever possible.
In case you are not familiar with it, $something+=$somethingelse is the same as $something=$sometime+$somethingelse, just a shorthand. $out is the running total, and each time around the inner loop (while $product), $out is increased by the rightmost digit (the ones column): $out+=$product%10 - see http://nz2.php.net/operators.arithmetic for more info, then $product is divided by 10 and converted to an integer, so 12 becomes 1.2, then 1, dropping the right-most digit.
Each time the inner loop is complete (all the digits of $product are used up, and $product is 0), the result (in $out) is copied to $product, and then you get back to the outer loop (to see if the sum of all these digits is now less than 10).
Also important is exactly where in each loop you print what. The first part, with the multiplication, is immediately in the '500' loop; the '||' happens once for each time '$product' is reduced to '$out'; the adding of the digits happens inside the innermost loop, with '+' either BEFORE each digit except the first, or AFTER each digit except the last. Since 'all except the last' is easier to calculate ($product>=10, watch those edge cases!), I chose that one.
Also note that, since I'm adding the digits from the right to the left, rather than left-to-right, the addition is reversed. I do not know if that will be an issue. Always consider if reversing the order will save you a lot of work. Obviously, if they NEED to be done in a particular order, then that might be a problem.
The result is:
for ($i=0; $i<500; $i++) {
$product = $i * 3; //Multiply set
print ($i . ' * 3 = ' .$product);
while ($product>10) {
print ' || ';
$out=0;
while ($product>0) {
print ($product%10);
if ($product>=10) {
print " + ";
}
$out+=$product%10;
$product=(integer)($product/10);
}
$product=$out;
print(' = ' .$product);
}
print "<br>";
};
I've decided to add this as a separate answer, because it uses a different approach to answer your question: the least amount of changes to fix the problem, rather than rewriting the code in an easy-to-read way.
There are two problems with your code, which require two separate fixes.
Problem 1: Your code does not add 3 digit (or more) numbers correctly.
If you look carefully at your code, you will notice that you are adding pairs of numbers ($one and $two); each time you add a pair of numbers, you print it out. This means that for the number 102, you are adding 1 and 0, printing out the results, then adding 0 and 2 and printing it out. Look carefully at your results, and you will see that 102 appears twice!
One way to fix this is to use $three and $four (4 digits is enough for 500*3). This is not good programming, because if you later need 5 digits, you will need to and $five, and so forth.
The way to program this is to start with a $sum of zero, then go through each digit, and add it to the sum, thusly:
$ii = 0;
$sum = 0;
while($ii <= $number_of_digits - 1){
$one = intval($addproduct[$ii]);
$sum = $sum + $one;
$ii++;
}
print($i . ' * 3 = ' .$product. ' || ' . $sum . '<br>');
};
The inner if disappears, of course, since it relates to $io, which we are no longer using.
Of course, now you lose your ability to print the individual digits as you are adding them up. If you want those in, and since we don't know in advance how many there are, you would have to keep a record of them. A string would be suitable for that. Here is how I would do it:
$ii = 0;
$sum = 0;
$maths = "";
while($ii <= $number_of_digits-1){
$one = intval($addproduct[$ii]);
if ($maths=="") {
$maths=$one;
} else {
$maths=$maths . " + " .$one;
}
$sum = $sum + $one;
$ii++;
}
print($i . ' * 3 = ' .$product. ' || ' . $maths . " = " . $sum . '<br>');
};
Note the lines with $math in them; there's one at the top, setting it to an empty string. Then, once we've decided on what number we're adding, we add this to $maths. The first time round is a special case, since we don't want "+" before our first digit, so we make an exception - if $maths is empty, we set it to $one; later times around the loop, it's not empty, so we add " + " . $one;
Problem 2: if the result of the addition is more than 1 digit long, go around again. And again, as many times as required.
At this point I would suggest a little refactoring: I would break the print statement into several parts. First the multiplication - that can easily be moved to the top, immediately after the actual multiplication. Printing the <br> can go at the end, immediately before the $i++. This also means you no longer need the else clause - it's already done. This only leaves the ' || ' . $maths . " = " . $sum. This is going to have to happen every time you go through the adding.
Now, replace your if($number_of_digits... with a while($number_of_digits...; this means it goes through as many times as is needed, if it's zero or 100. This does mean that you're going to have to update $product at the end of your loop, with $product = $sum; - put this immediately after the print statement. You will also need to update $number_of_digits; copy the line from the top to the end of the loop.
If you've been following along, you should have:
$i = 1; //Start with one
function count_digit($number) {
return strlen((string) $number);
};
while($i < 500){
$product = $i * 3; //Multiply set
print($i . ' * 3 = ' .$product); // Print basic multiplication
$number_of_digits = count_digit($product); //calls function to count digits of $sum
while ($number_of_digits > 1){ //if $sum has more than one digit add the digits together
$addproduct = strval($product);//seperates the digits of $sum
$ii = 0;
$sum = 0;
$maths = "";
while($ii <= $number_of_digits-1){
$one = intval($addproduct[$ii]);
if ($maths=="") {
$maths=$one;
} else {
$maths=$maths . " + " .$one;
}
$sum = $sum + $one;
$ii++;
}
print(" || " . $maths . " = " . $sum ); // print one lot of adding
$product=$sum;
$number_of_digits = count_digit($product); //calls function to count digits of $sum
};
Print ("<br>"); //go to next line
$i++; //add one
}
I am trying to create a binary/hexadecimal converter to convert a denary(base 10) number/value into binary and hexadecimal.
It works fine so far for binary until the input from the form is greater than 11 digits and over(string length), ruffly as it seems to variety. after 11 digits it starts adding " - " into the outcome. Im not sure were this is coming from as I don't have an " - " in the code.
I wasn't sure if this was something to do with large integers as I saw some other questions on that topic(not in php however it was java, so not sure if there is something simpler in php)
That said I was under the impression that form inputs were always strings.
To test if a variable is a number or a numeric string (such as form input, which is always a string), you must use is_numeric(). - from : http://www.php.net/manual/en/function.is-float.php
(haven't yet got to hexadecimal but needed to mention it as some of the following code contains parts for it.)
here is the php code (note: I do check user input just not added it yet)
$inpu = $_POST['number'];
$numinput = $_POST['number'];
if (is_numeric($numinput))
{
while ($numinput >= 1)
{
$binary .= $numinput % 2;
$numinput = $numinput / 2;
}
$mult = strlen($binary) % 4;
echo gettype($numinput) . "<br />";
echo gettype($binary) . "<br />";
echo gettype($mult) . "<br />";
echo $mult . "<br />";
while ($mult < 4)
{
$binary.= "0";
$mult++;
}
$revbinary = strrev($binary);
echo $inpu . " in binary = " . $revbinary ;
echo "<br /> <br />";
echo chunk_split($revbinary, 4);
echo "<br />" . gettype($revbinary) . "<br />";
echo gettype($inpu) . "<br />";
}
else
{
if (is_numeric($numinput))
{
echo "$numinput is over the max value of 255";
}
else
{
echo "your entry is not a vaild number <br />";
echo $numinput;
}
}
Im not looking for completed version of this code as you would ruin my fun, I am just wondering why there is a "-" being entered after 11 digits or so. It also did't add the symbol before I added :
$mult = strlen($binary) % 4;
echo $mult . "<br />";
while ($mult < 4)
{
$binary.= "0";
$mult++;
}
This was to split the binary into 4s ( 0011 1101 0010 0110 ).
Edit: wondered if this would be useful:
echo gettype($numinput); result double
echo gettype($binary); result string
echo gettype($mult); result integer
gettype($revbinary); result string
echo gettype($inpu); result string
still trying to work this out myself.
Any advice is much appreciated Thanks
I would suggest simply using decbin() and dechex(). Those are functions included in php, which do exactly what you're trying to accomplish.
You might want to check if it is a number first (like you are already doing).
Then cast it to an integer (through intval()) and then apply decbin() and dechex()
http://php.net/manual/de/function.decbin.php
http://www.php.net/manual/de/function.dechex.php
http://php.net/manual/de/function.intval.php
For example I have a mysql_num_rows results of 4,8,15,16,23,42 in a query that is inside a while loop of another query. My question is how can I total all the results inside that while loop? (Total of 133) Thanks.
EDIT:
How about if I want to get the percentage per each result of mysql_num_rows inside my while loop? Example: 4,8,15,16,23,42. Total is 108. $sum = 108. Percentage of 4 = 4/$sum = 3.7%, 8 = 8/$sum = 7.4% and so on..
Try something like this:
$Sum = 0;
while ($SomeInvariant)
{
mysql_query($SomeQuery);
$Sum += mysql_num_rows();
}
echo 'The sum is: ' . $Sum;
However, this approach is not very efficient (what if $SomeInvariant is true for many iterations, and your app has even more concurrent users?). To account for this, I would recommend restructuring your approach so the addition is done in SQL. This way, your query could look something like this: SELECT SUM(ColumnName) FROM ....
UPDATE: Addressing follow-up question in the comments
If you don't already have the sum available from the query, then you'll have to loop over the dataset twice. On the first pass, you'll calculate the sum. On the second pass, you'll calculate the ratio of each value to the sum.
For example:
$Sum = 0;
$Rows = array();
while ($SomeInvariant)
{
mysql_query($SomeQuery);
$Value = mysql_num_rows();
$Rows[] = $Value; // Push the value onto the row array
$Sum += $Value; // Add the value to the cumulative sum
}
echo 'The sum is: ' . $Sum;
foreach ($Rows as $Row)
{
echo $Row . '/' . $Sum . ' = ' . number_format($Row / $Sum) . '%';
}