Rounding up to next significant figure - php

I need to round up any integer between 1 and infinity in php to the next significant figure (though in practice I'm unlikely to need to round up infinity, so will be happy to settle on reasonable internal limits) eg:
$x <= 10 ? $x = 10
10 < $x <= 100 ? $x = 100
100 < $x <= 1000 ? $x = 1000
etc.
Round / ceil etc don't seem to do the job quite as planned. A pointer towards the correct algorhythm (or function?) would be much appreciated

i think this method will fix your problem:
function n($nr, $p = 10) {
if($nr <= $p) {
return $p;
}
return n($nr, $p*10);
}
heres the result:
echo n(1);
//output 10
echo n(232);
//output 1000
echo n(89289382);
//output 100000000

$x = pow(10,floor(log10($x)) + (floor(log10($x)) == log10($x) && $x!=1 ? 0:1) );

function my_ceil($in) {
if($in == 1) return $in;
if($in == pow(10, strlen($in)-1)) return $in;
return pow(10, strlen($in));
}
echo my_ceil(11); //100
echo my_ceil(10); //10

I think this is what you're looking for:
echo ceil($x / pow(10, strlen($x))) * pow(10, strlen($x));
Only works when $x is an integer, but you say in your question that that is indeed the case, so there's no issue (unless you try to later use it with numbers containing decimals).

This should do the trick:
<?php
function nextSignificantFeature($number){
$upper = pow(10, strlen($number));
return $number == $upper/10 ? $number : $upper;
}
?>

Actually there is the infinity number in PHP, so the implementation should deal with it as you wrote any number from 1 up to infinity Demo:
<?php
function n($number) {
if ($number < 1) {
throw new InvalidArgumentException('Number must be greater or equal 1.');
}
if ($number === INF) {
return INF;
}
$p = 10;
while($number > ($p*=10));
return $p;
}
echo n(1), "\n";
//output 10
echo n(232), "\n";
//output 1000
echo n(89289382), "\n";
//output 100000000
echo n(INF), "\n";
// output INF
echo n(-INF), "\n";
// throws exception 'InvalidArgumentException' with message 'Number must be greater or equal 1.'
This example does the iterative calculation in PHP userland code. There are some math functions in PHP that can do it inline like pow.

Related

Is there a faster way than x >= start && x <= end in PHP to test if an integer is between two integers?

This is a similar question to Fastest way to determine if an integer is between two integers (inclusive) with known sets of values, but the accepted answer will not work (as far as I know) in php due to php not being strictly typed and not having controllable integer overflow.
The use case here is to determine if an integer is between 65 and 90 (ASCII values for 'A' and 'Z'). These bounds might help optimize the solution due to 64 being a power of two and acting as boundary condition for this problem.
The only pseudo optimization I have come up with so far is:
//$intVal will be between 0 and 255 (inclusive)
function isCapital($intVal)
{
//255-64=191 (bit mask of 1011 1111)
return (($intVal & 191) <= 26) && (($intVal & 191) > 0);
}
This function is not much of an improvement (possibly slower) over a normal double comparison of $intVal >= 65 && $intVal <= 90, but it is just where I started heading while trying to optimize.
function isCapitalBitwise($intVal) {
return (($intVal & 191) <= 26) && (($intVal & 191) > 0);
}
function isCapitalNormal($intVal) {
return $intVal >= 65 && $intVal <= 90;
}
function doTest($repetitions) {
$i = 0;
$startFirst = microtime();
while ($i++ < $repetitions) {
isCapitalBitwise(76);
}
$first = microtime() - $startFirst;
$i = 0;
$startSecond = microtime();
while ($i++ < $repetitions) {
isCapitalNormal(76);
}
$second = microtime() - $startSecond;
$i = 0;
$startThird = microtime();
while ($i++ < $repetitions) {
ctype_upper('A');
}
$third = $startThird - microtime();
echo $first . ' ' . $second . ' ' . $third . PHP_EOL;
}
doTest(1000000);
On my system this returns:
0.217393 0.188426 0.856837
PHP is not as good at bitwise operations as compiled languages... but more importantly, I had to do a million comparisons to get less than 3 hundredths of a second of difference.
Even ctype_upper() is well in the range of "you might save a few seconds of CPU time per year" with these other ways of comparison, with the added bonus that you don't have to call ord() first.
Go for readability. Go for maintainability. Write your application, then profile it to see where your real bottlenecks are.
Instead of recreating the wheel, why not use the pre-built php method ctype_upper
$char = 'A';
echo ctype_upper($char) ? "It's uppercase" : "It's lowercase";
You can even pass in the integer value of a character:
echo ctype_upper($intVal) ? "It's uppercase" : "It's lowercase";
http://php.net/manual/en/function.ctype-upper.php
Even if you do find a method other than comparing via && or what I pasted above, it will be microseconds difference. You will waste hours coming up with a way to save a few seconds in the course of a year.
From How to check if an integer is within a range?:
t1_test1: ($val >= $min && $val <= $max): 0.3823 ms
t2_test2: (in_array($val, range($min, $max)): 9.3301 ms
t3_test3: (max(min($var, $max), $min) == $val): 0.7272 ms
You can also use range with characters (A, B, C...) but as you see it is not a good approach.
I think you will get best results by going native, but its only a fraction faster. Use ctype_upper directly. Here are my tests.
<?php
$numTrials = 500000;
$test = array();
for ($ii = 0; $ii < $numTrials; $ii++) {
$test[] = mt_rand(0, 255);
}
function compare2($intVal) {
return $intVal >= 65 && $intVal <= 90;
}
$tic = microtime(true);
for ($ii = 0; $ii < $numTrials; $ii++) {
$result = compare2($test[$ii]);
}
$toc = microtime(true);
echo "compare2...: " . ($toc - $tic) . "\n";
$tic = microtime(true);
for ($ii = 0; $ii < $numTrials; $ii++) {
$result = ctype_upper($test[$ii]);
}
$toc = microtime(true);
echo "ctype_upper: " . ($toc - $tic) . "\n";
echo "\n";
Which gives something pretty consistently like:
compare2...: 0.39210104942322
ctype_upper: 0.32374000549316

How I can create my own pow function using PHP?

I want to create a function in which I put two values (value and its power - Example function: multiply(3, 3) result 27). I have tried so far but failed, I have searched using Google but I have been unable to find any result because I don't know the name of this function.
What I want exactly:
3,3 => 3 x 3 x 3 = 27
4,4 => 4 x 4 x 4 x 4 = 256
What I tried:
function multiply($value,$power){
for($x = 1; $x <= $value; $x++ ){
return $c = $value * $power;
}
}
echo multiply(3,3);
The answer has already been accepted, but I had to come here and say that all answers here use a bad algorithm. There are better ones. Including very simple ones, like exponentiation by squaring that reduces the complexity from O(power) to O(log(power)).
The idea is to square the base while dividing the exponent by 2. For example
3^8 = 9^4 = 81^2 = 6561
There is a special case when the exponent is odd. In this case, you must store a separate variable to represent this factor:
2^10 = 4^5 = 16^2 * 4 = 256 * 4 = 1024
PHP isn't one of my strong skills, but the final algorithm is as simple as:
function multiply($value, $power){
$free = 1;
while ($power > 1) {
if ($power % 2 == 1)
$free *= $value;
$value *= $value;
$power >>= 1; //integer divison by 2
}
return $value*$free;
}
echo multiply(3, 3) . "\n";
echo multiply(2, 10) . "\n";
echo multiply(3, 8) . "\n";
Oopsika, couldn't have asked a more obvious question. Use the built-in function named pow (as in a lot of languages)
echo pow(3, 3);
Edit
Let's create our own function.
function raiseToPower($base,$exponent)
{
// multiply the base to itself exponent number of times
$result=1;
for($i=1;$i<=$exponent;$i++)
{
$result = $result * $base;
}
return $result;
}
function exponent($value,$power)
{
$c=1;
for($x = 1; $x <= $power; $x++ )
{
$c = $value * $c;
}
return $c;
}
If you have PHP >= 5.6 you can use the ** operator
$a ** $b Exponentiation Result of raising $a to the $b'th power.
echo 2 ** 3;
If you have PHP < 5.6 you can use pow:
number pow ( number $base , number $exp )
echo pow(2, 3);
Your own function is:
function multiply($value, $power) {
$result = 1;
for($x = 1; $x <= $power; $x++){
$result *= $value;
}
return $result;
}
echo multiply(3,3);
Read more at:
http://php.net/manual/en/language.operators.arithmetic.php
http://php.net/manual/en/function.pow.php
Just try to run this code I hope your problem will be solved.
If you defining any function then you have to call it return value.
<?php
function multiply($value,$exp)
{ $temp=1;
if($exp==0)
return $temp;
else
{
for($i=1;$i<=$exp;$i++)
$temp=$temp*$value;
return $temp;
}
}
echo multiply(5,6);
?>
echo "Enter number (will be mutiplied):".PHP_EOL;
$value = (int) readline("> ");
echo "Enter number for multiplier:".PHP_EOL;
$multiplier = (int) readline("> ");
function power(int $i, int $n):int {
$result =1;
for ($int = 1; $int < $n; $int++){
$result *= $i;
}
return $result;
}
echo power($value,$multiplier);

PHP check if is integer

I have the following calculation:
$this->count = float(44.28)
$multiple = float(0.36)
$calc = $this->count / $multiple;
$calc = 44.28 / 0.36 = 123
Now I want to check if my variable $calc is integer (has decimals) or not.
I tried doing if(is_int()) {} but that doesn't work because $calc = (float)123.
Also tried this-
if($calc == round($calc))
{
die('is integer');
}
else
{
die('is float);
}
but that also doesn't work because it returns in every case 'is float'. In the case above that should'n be true because 123 is the same as 123 after rounding.
Try-
if ((string)(int) $calc === (string)$calc) {
//it is an integer
}else{
//it is a float
}
Demo
As CodeBird pointed out in a comment to the question, floating points can exhibit unexpected behaviour due to precision "errors".
e.g.
<?php
$x = 1.4-0.5;
$z = 0.9;
echo $x, ' ', $z, ' ', $x==$z ? 'yes':'no';
prints on my machine (win8, x64 but 32bit build of php)
0.9 0.9 no
took a while to find a (hopefully correct) example that is a) relevant to this question and b) obvious (I think x / y * y is obvious enough).
again this was tested on a 32bit build on a 64bit windows 8
<?php
$y = 0.01; // some mambojambo here...
for($i=1; $i<31; $i++) { // ... because ...
$y += 0.01; // ... just writing ...
} // ... $y = 0.31000 didn't work
$x = 5.0 / $y;
$x *= $y;
echo 'x=', $x, "\r\n";
var_dump((int)$x==$x);
and the output is
x=5
bool(false)
Depending on what you're trying to achieve it might be necessary to check if the value is within a certain range of an integer (or it might be just a marginalia on the other side of the spectrum ;-) ), e.g.
function is_intval($x, $epsilon = 0.00001) {
$x = abs($x - round($x));
return $x < $epsilon;
};
and you might also take a look at some arbitrary precision library, e.g. the bcmath extension where you can set "the scale of precision".
You can do it using ((int) $var == $var)
$var = 9;
echo ((int) $var == $var) ? 'true' : 'false';
//Will print true;
$var = 9.6;
echo ((int) $var == $var) ? 'true' : 'false';
//Will print false;
Basically you check if the int value of $var equal to $var
round() will return a float. This is because you can set the number of decimals.
You could use a regex:
if(preg_match('~^[0-9]+$~', $calc))
PHP will convert $calc automatically into a string when passing it to preg_match().
You can use number_format() to convert number into correct format and then work like this
$count = (float)(44.28);
$multiple = (float)(0.36);
$calc = $count / $multiple;
//$calc = 44.28 / 0.36 = 123
$calc = number_format($calc, 2, '.', '');
if(($calc) == round($calc))
die("is integer");
else
die("is not integer");
Demo
Ok I guess I'am pretty late to the party but this is a alternative using fmod() which is a modulo operation. I simply store the fraction after the calculation of 2 variables and check if they are > 0 which would imply it is a float.
<?php
class booHoo{
public function __construct($numberUno, $numberDos) {
$this->numberUno= $numberUno;
$this->numberDos= $numberDos;
}
public function compare() {
$fraction = fmod($this->numberUno, $this->numberDos);
if($fraction > 0) {
echo 'is floating point';
} else {
echo 'is Integer';
}
}
}
$check= new booHoo(5, 0.26);
$check->compare();
Eval here
Edit: Reminder Fmod will use a division to compare numbers the whole documentation can be found here
if (empty($calc - (int)$calc))
{
return true; // is int
}else{
return false; // is no int
}
Try this:
//$calc = 123;
$calc = 123.110;
if(ceil($calc) == $calc)
{
die("is integer");
}
else
{
die("is float");
}
you may use the is_int() function at the place of round() function.
if(is_int($calc)) {
die('is integer');
} else {
die('is float);
}
I think it would help you
A more unorthodox way of checking if a float is also an integer:
// ctype returns bool from a string and that is why use strval
$result = ctype_digit(strval($float));

Improve performance of php on local server

I have a XAMPP install, with pretty much the default config.
Performance isn't much of a problem in general as I use PHP mostly to run web pages and small web apps. Waiting a couple seconds for a page is not unusual.
However, I have recently taken up the problems from Project Euler and decided to do them in PHP.
Try as I may, I couldn't get my code to run in less than 1 minute 1 second (optimized down from almost 3 min) and I was getting pretty embarrassed, especially considering most posters on Pjt Euler reported times of 1-3 seconds. (#7, find the 10001th prime)
I ported my code to C#, and the same task completed in a blink. 0.4 seconds. Same algorithm, the only notable difference in the code is that I used a List in C# to replace the array I was using in PHP.
While I did expect C# to outperform php, this difference leads me to suspect a gross configuration problem, but I have no idea where to look.
What could be the cause of this poor performance?
Edit: Here is the code:
In PHP:
/*
* Project Euler #7:
* By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13.
* What is the 10001st prime number?
*/
ini_set('max_execution_time', 300);
echo "start time:" . date("i:s:u") . "<br />";
function isPrime($number, $prevPrimes)
{
foreach ($prevPrimes as $key =>$prime)
{
if ($prime == 1)
{
continue;
}
elseif ($number % $prime == 0)
{
return 0;
}
}
// If we get to here, $number is prime
return $number;
}
$primes = array();
$i = 0;
$nbPrimes = 0;
while ($nbPrimes <10001)
{
$i++;
if ($i % 2 != 0)
{
$result = isPrime($i, $primes);
if ($result != 0)
{
$primes[] = $i;
$nbPrimes++;
}
}
}
echo "#$nbPrimes: $result<br>";
echo "End time:" . date("i:s:u") . "<br />";
In C#:
public static void RunSnippet()
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
List<int> primes = new List<int>();
int i = 0;
int nbPrimes = 0;
int result =0;
while (nbPrimes <10001)
{
i++;
if (i % 2 != 0)
{
result = isPrime(i, primes);
if (result != 0)
{
primes.Add(i);
nbPrimes++;
}
}
}
stopwatch.Stop();
Console.WriteLine("Time elapsed: {0}",
stopwatch.Elapsed);
Console.WriteLine ("#" + nbPrimes + ": " + result.ToString());
}
public static int isPrime(int number, List<int> prevPrimes)
{
foreach (int prime in prevPrimes)
{
if (prime == 1)
{
continue;
}
else if (number % prime == 0)
{
return 0;
}
}
// If we get to here, number is prime
return number;
}
"Use the force ..." of math! Just throwing some code pointless. Here are just a few points that can boost the performance.
why you are using array to match the number against?
the foreach function is thus ineffective - the cycle should end at floor(sqrt(number))
example: sqrt(64) = 8 -> all prime dividers will be from 1 to 8. The others will be product of them( 32 = 4 x 8 = 2x2x2x2x2 )
use formulas to jump to the next possibly prime number
math:
numbers divisable by 2 - 2, 4, 6, 8, 10, 12 -> 2k+1 = 2x1+1 = 3, 5, .....
numbers divisable by 3 - 3, 6, 9, 12 -> we already have 6 and 12, so 3, 9, 15, 21 -> 3(2k-1) = 3(2x1-1) = 3, 9, ...
here is some pseudo code from hk admin at project euler
isPrime ( number )
{
if ( number == 1 ) return false
elseif ( number < 4 ) return true
elseif ( number % 2 == 0 ) return false
elseif ( number < 9 ) return true
elseif ( number % 3 == 0 ) return false
else
r = floor ( sqrt ( number ) )
f = 5
while ( f <= r )
{
if ( number % f == 0 ) return false
if ( number % ( f + 2 ) == 0 ) return false
f = f + 6
}
return true
}
PS
About the difference in the speed of the execution - PHP is interpreted language, to view the result in browser you have 3 programs running - browser, server, php interpreter. You make a http request, the server calls php (and probably a bunch of other stuff, logging for example),php reads the script and executes it. There are much more steps than in C#.
In C# the compiled code is executed.
FINAL EDIT
Here is the PHP code from Bakudan's logic, which returns this result:
start time:44:25:000000
#10001: 104759
End time:44:26:000000
The Code:
<?php
echo "start time:" . date("i:s:u") . "\n";
function isPrime($number, &$primes)
{
if ($number === 1) return false;
elseif ($number %2 === 0) return false;
elseif ($number < 4) return true;
elseif ($number < 9) return true;
elseif ($number %3 === 0) return false;
else $r = floor(sqrt($number));
$f = 5;
while ($f <= $r) {
if ($number % $f ===0) return false;
if ($number % ($f+2) === 0) return false;
$f = $f + 6;
}
return true;
}
$primes = array();
$nbPrimes = $i = 0;
while ($nbPrimes < 10001)
{
$i++;
if (isPrime($i, $primes) !== false)
{
$primes[] = $i;
$nbPrimes++;
}
}
echo "#$nbPrimes: " . end($primes) . "\n";
echo "End time:" . date("i:s:u") . "\n";
Bakudan gave me the pseudo code, I Just translated and wrote it out for the OP's script above.
EDIT 2
I cleaned up the code a bit, didn't improve anything, may enhance "readability". But yea, I think this is the best you will get with PHP, which on an i7 without apache yields 5 seconds.
<?php
echo "start time:" . date("i:s:u") . "\n";
function isPrime($number, &$primes)
{
foreach($primes as $prime) {
if ($number % $prime === 0 && $prime > 1)
return false;
}
}
$primes = array();
$nbPrimes = $i = 1;
while ($nbPrimes <= 10001)
{
if ($i % 2 !== 0 && isPrime($i, $primes) !== false)
{
$primes[] = $i;
$nbPrimes++;
}
$i++;
}
echo "#$nbPrimes: " . end($primes) . "\n";
echo "End time:" . date("i:s:u") . "\n";
EDIT
Knocked another second off by moving the $prime === 1 to be after the $number % $prime check in the same if statement.
start time:29:40:000000
#10001: 104743
End time:29:45:000000
Taking Hannes suggestion of strict checking and passing the array as reference plus adding a few tweaks of my own (modifying the array inside the function):
ini_set('max_execution_time', 300);
echo "start time:" . date("i:s:u") . "\n";
function isPrime($number, &$prevPrimes)
{
foreach ($prevPrimes as $prime) {
if ($number % $prime === 0 && $prime !== 1)
{
return false;
}
}
// If we get to here, $number is prime
$prevPrimes[] = $number;
return $number;
}
$primes = array();
$i = 0;
$nbPrimes = 0;
while ($nbPrimes < 10001)
{
$i++;
if ($i % 2 !== 0)
{
$result = isPrime($i, $primes);
if ($result !== 0)
{
$nbPrimes++;
}
}
}
echo "#$nbPrimes: $result\n";
echo "End time:" . date("i:s:u") . "\n";
Which ended up being:
start time:52:08:000000
#10001: 104743
End time:52:15:000000
VS your code:
start time:50:44:000000
#10001: 104743
End time:51:17:000000
A good improvement there, but nothing like C#, just goes to show the power of a compiled language :)
While I did expect C# to outperform
php, this difference leads me to
suspect a gross configuration problem,
but I have no idea where to look.
Firing the PHP engine creates a little overhead for the webserver. The way PHP is loaded (e.g. loaded as a module on server startup or loaded on demand for every .php request) determines how much overhead is involved. Then on windows there are two variants of PHP available: thread-safe and non thread-safe, the latter one is claimed to be faster.
If its a XAMPP configuration problem, I think you can isolate it by running the test 3 times on your webserver and note down the average time. Then run the same script via PHP CLI 3 times and note down the average. If the difference is noticeable then you might blame XAMPP. You should be able to locate the PHP CLI binary somewhere inside the XAMPP installation folder.
On my system I get these results:
PHP-CLI: #10001: 104743 -- Time taken: 30.25 second(s)
PHP on IIS/FastCGI: #10001: 104743 -- Time taken: 29.89 second(s)
PHP on Apache/CGI: #10001: 104743 -- Time taken: 29.93 second(s)
Not much of a difference -- I would rather optimize the code.
EDIT
Same machine and everything but execution time brought down from ~30 seconds to ~5.85 seconds with this revised code. The only thing worth mentioning is that that I used a global array instead of passing it by value every time the isPrime function is called (104743 times to be precise). Passing the array by reference also results in similar execution time, give or take 1 second. The comparison operators shave off just a second or two but not much.
/*
* Project Euler #7:
* By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13.
* What is the 10001st prime number?
*/
ini_set('max_execution_time', 300);
$t0 = microtime(true);
$primes = array();
function isPrime($number)
{
global $primes;
foreach ($primes as $prime)
{
if ($prime === 1)
{
continue;
}
elseif ($number % $prime === 0)
{
return 0;
}
}
return $number;
}
$i = 0;
$nbPrimes = 0;
while ($nbPrimes < 10001)
{
$i++;
if ($i % 2 !== 0)
{
$result = isPrime($i);
if ($result !== 0)
{
$primes[] = $i;
$nbPrimes++;
}
}
}
$t1 = microtime(true);
echo sprintf('#%d: %d -- Time taken: %.2f second(s)', $nbPrimes, $result, $t1 - $t0);

PHP: Simple recursive function into iterative function

I was going to do it in C but was confused, so I turned to PHP and was able to copy a recursive function to do this. I am converting an integer into a string with math. Here it is:
function intToString($myDecimal){
if($myDecimal < 10) {
return $myDecimal;
}
return intToString(($myDecimal / 10)) . ($myDecimal % 10);
}
I was able to convert a recursive factorial function before.. but with this I just have no clue.. My attempt is as follows:
function intToStringIter($myDecimal){
$out = "";
while($myDecimal > 10) {
$myDecimal /= 10;
$out .= $myDecimal;
}
$out .= $myDecimal % 10;
return $out;
}
I think I am too tired to see the proper logic at the moment.. It returns 22 instead of 20, I cannot wrap my head around what is correct. Do you see what I am doing wrong?
If you're looking for a conversion to string for big unsigned integers, the code is actually:
function intToString($myDecimal)
{
return sprintf('%u', $myDecimal);
}
If you need to do it with iteration:
function intToString($myDecimal)
{
$result = '';
while ($myDecimal > 9) {
$result = ($myDecimal % 10) . $result;
$myDecimal /= 10;
}
return $myDecimal . $result;
}
UPDATE: My bad, digits were inserted in reversed order. Now it should work. Sorry, untested too.
PHP is not very strict with variables. An integer will become an float if the situation likes it. In your code, $myDecimal /= 10 could make a float of $myDecimal. The following forces $myDecimal to stay an integer. Note: you should pass only integers, if you're passing 9.99, the output would still be 9.99 because 9.99 < 10.
function intToStringIter($myDecimal){
$out = "";
while($myDecimal >= 10) {
$myDecimal = (int) ($myDecimal / 10);
$out .= $myDecimal;
}
$out .= $myDecimal % 10;
return $out;
}

Categories