Why is the last number (1) printed? - php

The code:
<?php
$start = 0;
$stop = 1;
$step = ($stop - $start)/10;
$i = $start + $step;
while ($i < $stop) {
echo($i . "<br/>");
$i += $step;
}
?>
The output:
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1 <-- notice the 1 printed when it shouldn't
Created a fiddle
One more: if you set $start = 1 and $stop = 2 it works fine.
Using: php 5.3.27
Why is the 1 printed?

Because not only float math is flawed, sometimes its representation is flawed too - and that's the case here.
You don't actually get 0.1, 0.2, ... - and that's quite easy to check:
$start = 0;
$stop = 1;
$step = ($stop - $start)/10;
$i = $start + $step;
while ($i < $stop) {
print(number_format($i, 32) . "<br />");
$i += $step;
}
The only difference here, as you see, is that echo replaced with number_format call. But the results are drastically different:
0.10000000000000000555111512312578
0.20000000000000001110223024625157
0.30000000000000004440892098500626
0.40000000000000002220446049250313
0.50000000000000000000000000000000
0.59999999999999997779553950749687
0.69999999999999995559107901499374
0.79999999999999993338661852249061
0.89999999999999991118215802998748
0.99999999999999988897769753748435
See? Only one time it was 0.5 actually - because that number can be stored in a float container. All the others were only approximations.
How to solve this? Well, one radical approach is using not floats, but integers in similar situations. It's easy to notice that have you done it this way...
$start = 0;
$stop = 10;
$step = (int)(($stop - $start) / 10);
$i = $start + $step;
while ($i < $stop) {
print(number_format($i, 32) . "<br />");
$i += $step;
}
... it would work ok:
Alternatively, you can use number_format to convert the float into some string, then compare this string with preformatted float. Like this:
$start = 0;
$stop = 1;
$step = ($stop - $start) / 10;
$i = $start + $step;
while (number_format($i, 1) !== number_format($stop, 1)) {
print(number_format($i, 32) . "\n");
$i += $step;
}

The problem is that the number in the variable $i is not 1 (when printed). Its actual just less than 1. So in the test ($i < $stop) is true, the number is converted to decimal (causing rounding to 1), and displayed.
Now why is $i not 1 exactly? It is because you got there by saying 10 * 0.1, and 0.1 cannot be represented perfectly in binary. Only numbers which can be expressed as a sum of a finite number of powers of 2 can be perfectly represented.
Why then is $stop exactly 1? Because it isn't in floating point format. In other words, it is exact from the start -- it isn't calculated within the system used floating point 10 * 0.1.
Mathematically, we can write this as follows:
A 64 bit binary float can only hold the first 27 non-zero terms of the sum which approximates 0.1. The other 26 bits of the significand remain zero to indicate zero terms. The reason 0.1 isn't physically representable is that the required sequence of terms is infinite. On the other hand, numbers like 1 require only a small finite number of terms and are representable. We'd like that to be the case for all numbers. This is why decimal floating point is such an important innovation (not widely available yet). It can represent any number that we can write down, and do so perfectly. Of course, the number of available digits remains finite.
Returning to the given problem, since 0.1 is the increment for the loop variable and isn't actually representable, the value 1.0 (although representable) is never precisely reached in the loop.

If your step will always be a factor of 10, you can accomplish this quickly with the following:
<?php
$start = 0;
$stop = 1;
$step = ($stop - $start)/10;
$i = $start + $step;
while (round($i, 1) < $stop) { //Added round() to the while statement
echo($i . "<br/>");
$i += $step;
}
?>

Related

Using PHP to calculate Pi

Okay this is just something me and my coworker are playing with.
We know PHP has it's own PI function but this came forth out of a theory and curiosity.
So we were wondering if and how PHP was able to calculate pi.
Formule of pi = π= 4/1 - 4/3 + 4/5 - 4/7 + 4/9...
Here is what we did:
$theValue = 100;// the max
for ($i=1; $i<$theValue; $i++){
if ($i % 2 == 1){
$iWaardes[] = 4 / $i; // divide 4 by all uneven numbers and store them in an array
}
}
// Use the array's $keys as incrementing numbers to calculate the $values.
for ($a=0, $b=1, $c=2; $a<$theValue; $a+=3, $b+=3, $c+=3 ){
echo ($iWaardes[$a] - $iWaardes[$b] + $iWaardes[$c]).'<br>';
}
So now we have a loop that calculated the first series of 4/1 - 4/3 + 4/5 but it stops after that and starts over with the following 3 sequences.
How can we make it run the entire $theValue and calculate the whole series?
Please keep in mind that this is nothing serious and just a fun experiment for us.
You're overthinking this. Just use the modulo to decide if you want to add or subtract and do it in place.
$theValue = 100;// the max
$pi = 0;
for ($i=1; $i<$theValue; $i++){
if ($i % 2 == 1){
$pi += 4.0 / ($i * 2 - 1);
} else {
$pi -= 4.0 / ($i * 2 - 1);
}
}
Just use one loop. Have a $bottom variable that you add 2 on each iteration, divide by it, and add it/subtract it depending on the modulo:
$theValue = 10000; // the max
$bottom = 1;
$pi = 0;
for ($i = 1; $i < $theValue; $i++) {
if ($i % 2 == 1) {
$pi += 4 / $bottom;
} else {
$pi -= 4 / $bottom;
}
$bottom += 2;
}
var_dump($pi); // 3.14169266359
Demo
What's wrong with your code (other than not dividing by the appropriate number) is the second loop. You're for some reason printing out the stored numbers 3 by 3. This, until $a, that increases by 3, is lower than $theValue which is much higher. So, for example, if $theValue is 10, you only need 2 loops before you start getting out of bound errors.
pi() Returns an approximation of pi. The returned float has a precision based on the precision directive in php.ini, which defaults to 14. Also, you can use the M_PI constant which yields identical results to pi()
source
Using PHP we can also calculate Pi, albeit very slowly.
$pi = 4; $top = 4; $bot = 3; $minus = TRUE;
$accuracy = 1000000;
for($i = 0; $i < $accuracy; $i++)
{
$pi += ( $minus ? -($top/$bot) : ($top/$bot) );
$minus = ( $minus ? FALSE : TRUE);
$bot += 2;
}
print "Pi ~=: " . $pi;
This method of calculating Pi is slow, but it is easy to read code.
You can read more about this method here:
http://en.wikipedia.org/wiki/Leibniz_formula_for_%CF%80
If you increase the $accuracy variable, Pi will be calculated more and more accurately. Depending on how fast your web server is, you can calculate the first 6 digits of Pi fairly quickly.
The time it takes to calculate each succeeding number goes up exponentially however. To calculate 20 digits of Pi using this method method could take years.

generating same number with the given length

I have this math assignment that I should make into code.
I've tried all I thought of but I couldn't find a solution.
All this should be done without using php functions, only math operations.
You can use while, for, and such...
So I have number for example 9
Now I should create number of the length 9 which would be 999999999
If I had, for example, number 3, then the result should be 333.
Any ideas?
$gen = -1;
while($highest > 0) {
$gen = $highest + ($highest * 10);
$highest = $highest - 1;
}
echo $gen;
Here is a method that does not build a string; it uses pure math. (There will be many, many ways to do this task)
$x=9;
$result=0;
for($i=$x; $i; --$i){ // this looping expression can be structured however you wish potato-potatoe
$result+=$x*(10**($i-1)); // x times (10 to the power of (i-1))
}
echo $result;
// 999999999
*note: ** acts like pow() if you want to look it up.
Late edit: here is a clever, little loopless method (quietly proud). I am only calling range() and foreach() to demo; it is not an integral component of my method.
Demo: https://3v4l.org/GIjfG
foreach(range(0,9) as $n){
// echo "$n -> ",(integer)(1/9*$n*(10**$n)-($n/10)),"\n";
// echo "$n -> ",(1/9*$n*(10**$n)-(1/9*$n)),"\n";
// echo "$n -> ",(int)(1/9*10**$n)*$n,"\n";
// echo "$n -> ",(int)(10**$n/9)*$n,"\n";
echo "$n -> ",(10**$n-1)/9*$n,"\n";
}
Output:
0 -> 0
1 -> 1
2 -> 22
3 -> 333
4 -> 4444
5 -> 55555
6 -> 666666
7 -> 7777777
8 -> 88888888
9 -> 999999999
1/9 is the hero of this method because it generates .111111111(repeating). From this float number, I am using 10**$n to "shift" just enough 1s to the left side of the decimal point, then multiplying this float number by $n, then the float must be converted to an integer to complete.
Per #axiac's comment, the new hero is 10**$n-1 which generates a series of nines to the desired length (no float numbers). Next divide the nines by nine to generate a series of ones which becomes the perfect multiplier. Finally, multiply the series of ones and the input number to arrive at the desired output.
There are two operations you need to accomplish:
given a number $number, append the digit $n to it;
repeat operation #1 some number of times ($n times).
Operation #1 is easy:
$number = $number * 10 + $n;
Operation #2 is even easier:
for ($i = 0; $i < $n; $i ++)
What else do you need?
Initialization of the variable used to store the computed number:
$number = 0;
Put them in order and you get:
// The input digit
// It gives the length of the computed number
// and also its digits
$n = 8;
// The number we compute
$number = 0;
// Put the digit $n at the end of $number, $n times
for ($i = 0; $i < $n; $i ++) {
$number = $number * 10 + $n;
}
// That's all
If intval() is accepted:
$result = '';
$input = 9;
for($i=0; $i < $input; $i++){
$result .= $input;
}
$result = intval($result);
else:
$result = 0;
$input = 9;
for($i=0; $i < $input; $i++){
$factor = 1;
for($j = 0; $j < $i; $j++){
$factor *= 10;
}
$result += $input * $factor;
}
=>
9 + 90 + 900 + 9000 + 90000...

Float number and zero comparison

I have a simple PHP task, to sum all number's digits.
$number = 345;
$digit = $number;
$sum = 0;
while ($number > 0) {
$digit = $number % 10;
$sum += $digit;
$number /= 10;
}
This solution would give correct result. However, I'm aware that it will enter loop way more than three times. And eventually it will become equal to zero.
Why is that happening? At what time, floats become zero? Just by following math principles, this would be an infinite loop, right? And since there are more than 3, 4 and 5 digits, how end result is not greater than 12 (even for that little amount).
P.S. I know that I should solve this by rounding $number value for example, but I'm just curios about floats and its behaviour.
When you update number you should really be doing this
$number -= $digit;
$number /= 10;
Floats are platform specific, check out this link
http://php.net/manual/en/language.types.float.php

How can I make a counter in PHP that counts up to 10 (including "first decimal-place" numbers)?

I'm trying to make a PHP counter and this is what I have:
<?PHP
for ($i = 0; $i < 10; $i ++) {
print "$i";
}
?>
It's quite a simple counter but I was wondering if it could count all the decimal numbers (only one decimal place) as well, is there any way I could do that?
This is what I would like:
0.1,
0.2,
0.3,
...
9.8,
9.9,
10.0.
It's impossible to count from 1 to 10, including ALL decimals. There would be infinitely many of them.
However, you could count in tenths:
<?php
for ($i = 0; $i <= 10; $i+=0.1) {
print "$i\r\n";
}
?>
You need to decide on a precision. Let's say you want a decimal precision of 2 decimal places for this exercise (but this could obviously be changed in code). My suggestion would be to simply implement an integer counter between 0 and 1000 and then divide counter value by 100 to get decimal values.
$decimal_precision = 2;
$counter_limit = 10;
$counter_ratio = (int)pow(10, $decimal_precision);
$integer_limit = $counter_limit * $counter_ratio;
for($i = 1; $i <= $integer_limit; $i++) {
echo (float) $i / $counter_ratio;
}

Project Euler #23: Non-abundant sums

I'm struggling with Project Euler problem 23: Non-abundant sums.
I have a script, that calculates abundant numbers:
function getSummOfDivisors( $number )
{
$divisors = array ();
for( $i = 1; $i < $number; $i ++ ) {
if ( $number % $i == 0 ) {
$divisors[] = $i;
}
}
return array_sum( $divisors );
}
$limit = 28123;
//$limit = 1000;
$matches = array();
$k = 0;
while( $k <= ( $limit/2 ) ) {
if ( $k < getSummOfDivisors( $k ) ) {
$matches[] = $k;
}
$k++;
}
echo '<pre>'; print_r( $matches );
I checked those numbers with the available on the internet already, and they are correct. I can multiply those by 2 and get the number that is the sum of two abundant numbers.
But since I need to find all numbers that cannot be written like that, I just reverse the if statement like this:
if ( $k >= getSummOfDivisors( $k ) )
This should now store all, that cannot be created as the sum of to abundant numbers, but something is not quit right here. When I sum them up I get a number that is not even close to the right answer.
I don't want to see an answer, but I need some guidelines / tips on what am I doing wrong ( or what am I missing or miss-understanding ).
EDIT: I also tried in the reverse order, meaning, starting from top, dividing by 2 and checking if those are abundant. Still comes out wrong.
An error in your logic lies in the line:
"I can multiply those by 2 and get the number that is the sum of two abundant numbers"
You first determine all the abundant numbers [n1, n2, n3....] below the analytically proven limit. It is then true to state that all integers [2*n1, 2*n2,....] are the sum of two abundant numbers but n1+n2, and n2+n3 are also the sum of two abundant numbers. Therein lies your error. You have to calculate all possible integers that are the sum of any two numbers from [n1, n2, n3....] and then take the inverse to find the integers that are not.
I checked those numbers with the available on the internet already, and they are correct. I can multiply those by 2 and get the number that is the sum of two abundant numbers.
No, that's not right. There is only one abundant number <= 16, but the numbers <= 32 that can be written as the sum of abundant numbers are 24 (= 12 + 12), 30 (= 12 + 18), 32 (= 12 + 20).
If you have k numbers, there are k*(k+1)/2 ways to choose two (not necessarily different) of them. Often, a lot of these pairs will have the same sum, so in general there are much fewer than k*(k+1)/2 numbers that can be written as the sum of two of the given k numbers, but usually, there are more than 2*k.
Also, there are many numbers <= 28123 that can be written as the sum of abundant numbers only with one of the two abundant numbers larger than 28123/2.
This should now store all, that cannot be created as the sum of to abundant numbers,
No, that would store the non-abundant numbers, those may or may not be the sum of abundant numbers, e.g. 32 is a deficient number (sum of all divisors except 32 is 31), but can be written as the sum of two abundant numbers (see above).
You need to find the abundant numbers, but not only to half the given limit, and you need to check which numbers can be written as the sum of two abundant numbers. You can do that by taking all pairs of two abundant numbers (<= $limit) and mark the sum, or by checking $number - $abundant until you either find a pair of abundant numbers or determine that none sums to $number.
There are a few number theoretic properties that can speed it up greatly.
Below is php code takes 320 seconds
<?php
set_time_limit(0);
ini_set('memory_limit', '2G');
$time_start = microtime(true);
$abundantNumbers = array();
$sumOfTwoAbundantNumbers = array();
$totalNumbers = array();
$limit = 28123;
for ($i = 12; $i <= $limit; $i++) {
if ($i >= 24) {
$totalNumbers[] = $i;
}
if (isAbundant($i)) {
$abundantNumbers[] = $i;
}
}
$countOfAbundantNumbers = count($abundantNumbers);
for ($j = 0; $j < $countOfAbundantNumbers; $j++) {
if (($j * 2) > $limit)
break; //if sum of two abundant exceeds limit ignore that
for ($k = $j; $k < $countOfAbundantNumbers; $k++) { //set $k = $j to avoid duble addtion like 1+2, 2+1
$l = $abundantNumbers[$j] + $abundantNumbers[$k];
$sumOfTwoAbundantNumbers[] = $l;
}
}
$numbers = array_diff($totalNumbers, $sumOfTwoAbundantNumbers);
echo '<pre>';print_r(array_sum($numbers));
$time_end = microtime(true);
$execution_time = ($time_end - $time_start);
//execution time of the script
echo '<br /><b>Total Execution Time:</b> ' . $execution_time . 'seconds';
exit;
function isAbundant($n) {
if ($n % 12 == 0 || $n % 945 == 0) { //first even and odd abundant number. a multiple of abundant number is also abundant
return true;
}
$k = round(sqrt($n));
$sum = 1;
if ($n >= 1 && $n <= 28123) {
for ($i = 2; $i <= $k; $i++) {
if ($n % $i == 0)
$sum+= $i + ( $n / $i);
if ($n / $i == $i) {
$sum = $sum - $i;
}
}
}
return $sum > $n;
}

Categories