We are looking for the Nth root in PHP. We need to do this with a very large number, and the windows calculator returns 2. With the following code we are getting 1. Does anybody have an idea how this works?
echo bcpow(18446744073709551616, 1/64);
Well it seems that PHP and the BC lib has some limits, and after searching on the internet i found this interesting article/code:
So you should use this function:
<?php
function NRoot($num, $n) {
if ($n<1) return 0; // we want positive exponents
if ($num<=0) return 0; // we want positive numbers
if ($num<2) return 1; // n-th root of 1 or 2 give 1
// g is our guess number
$g=2;
// while (g^n < num) g=g*2
while (bccomp(bcpow($g,$n),$num)==-1) {
$g=bcmul($g,"2");
}
// if (g^n==num) num is a power of 2, we're lucky, end of job
if (bccomp(bcpow($g,$n),$num)==0) {
return $g;
}
// if we're here num wasn't a power of 2 :(
$og=$g; // og means original guess and here is our upper bound
$g=bcdiv($g,"2"); // g is set to be our lower bound
$step=bcdiv(bcsub($og,$g),"2"); // step is the half of upper bound - lower bound
$g=bcadd($g,$step); // we start at lower bound + step , basically in the middle of our interval
// while step!=1
while (bccomp($step,"1")==1) {
$guess=bcpow($g,$n);
$step=bcdiv($step,"2");
$comp=bccomp($guess,$num); // compare our guess with real number
if ($comp==-1) { // if guess is lower we add the new step
$g=bcadd($g,$step);
} else if ($comp==1) { // if guess is higher we sub the new step
$g=bcsub($g,$step);
} else { // if guess is exactly the num we're done, we return the value
return $g;
}
}
// whatever happened, g is the closest guess we can make so return it
return $g;
}
echo NRoot("18446744073709551616","64");
?>
Hope this was helpful ...
I had problems with HamZa's solution getting to work with arbitrary precission, so i adopted it a little.
<?php
function NthRoot($Base, $NthRoot, $Precision = 100) {
if ($NthRoot < 1) return 0;
if ($Base <= 0) return 0;
if ($Base < 2) return 1;
$retVal = 0;
$guess = bcdiv($Base, 2, $Precision);
$continue = true;
$step = bcdiv(bcsub($Base, $guess, $Precision), 2, $Precision);
while ($continue) {
$test = bccomp($Base, bcpow($guess, $NthRoot, $Precision), $Precision);
if ($test == 0) {
$continue = false;
$retVal = $guess;
}
else if ($test > 0) {
$step = bcdiv($step, 2, $Precision);
$guess = bcadd($guess, $step, $Precision);
}
else if ($test < 0) {
$guess = bcsub($guess, $step, $Precision);
}
if (bccomp($step, 0, $Precision) == 0) {
$continue = false;
$retVal = $guess;
}
}
return $retVal;
}
Related
I had a need to generate a list of four-digit numbers for use as codes. The digits should not repeat, and each next digit should not be sequential. There were some questions that were similar but not enough for me to answer. I chose to share my function instead. It did not matter if reverse numbers were in the list e.g. 1357 > 7531.
It occurred to me that it there may be an opportunity for a recursive function, possibly to return five or six-digit numbers. Improvements to my function are most welcome.
public function codeList() {
$data = [];
for ($ii=0; $ii < 10; $ii++) {
for ($jj=0; $jj < 10; $jj++) {
for ($kk=0; $kk < 10; $kk++) {
for ($ll=0; $ll < 10; $ll++) {
$str = "{$ii}{$jj}{$kk}{$ll}";
$arr = str_split($str);
if (count($arr) === count(array_unique($arr))) {
if (($arr[0] + 1 != $arr[1]) && ($arr[1] + 1 != $arr[2]) && ($arr[2] + 1 != $arr[3])) {
$data[] = $str;
}
}
}
}
}
}
return $data;
} # END FUNCTION codeList
First than nothing I'm not a native guy so sorry for all those mistakes.
I'm trying to get the largest palindromic product between two integers, for example; 3 and 11, the largest will be 11*11=121.
I tried with this.
function Pallendrome($str) : bool {
return (strval($str) == strrev(strval($str))) ? true : false;
}
function largestPalindromicProduct($lower, $upper) {
$array = array();
for($it=$upper; $it >= $lower; $it--){
for($it_=$upper; $it_ >= $lower; $it_--){
$num = $it*$it_;
if(Pallendrome($num)) { array_push($array, $num); }
}
}
if(empty($array)) { return NAN; }
else{ ksort($array); return $array[0];}
}
But, I'd need to get a way to optimize it 'cause it's taking a long time due to the numbers introduced in, are kind of big.
Do you guys have some idea for it? Thank ya!.
I'm sure the folks over at math.stackexchange.com could help you with a better algorithm, but for the purposes of optimizing what you've got thus far, here's a summation of all my comments:
function largestPalindromicProduct($lower, $upper)
{
$largest = 0;
for ($it = $upper; $it >= $lower; $it--) {
for ($it_ = $upper; $it_ >= $lower; $it_--) {
$num = $it * $it_;
// If we're on the first iteration and we have a product lower than the
// largest we've found so far, then we know we can never get a larger
// number (because we're counting down) and we can abort immediately.
if ($num <= $largest) {
if ($it_ == $upper) {
break 2;
}
// Otherwise, we can at least abort the rest of this subloop.
break;
}
// Only check if it's a palindrome once we've passed all the other checks.
if ($num == strrev($num)) {
$largest = $num;
}
}
}
return $largest;
}
I tried to find For a given positive integer Z, check if Z can be written as PQ, where P and Q are positive integers greater than 1. If Z can be written as PQ, return 1, else return 0
I tried lots with online solution,
Check if one integer is an integer power of another
Finding if a number is a power of 2
but it's not what i need , any hint or any tips?
Here's the naive method - try every combination:
function check($z) {
for($p = 2; $p < sqrt($z); $p++) {
if($z % $p > 0) {
continue;
}
$q = $p;
for($i = 1; $q < $z; $i++) {
$q *= $p;
}
if($q == $z) {
//print "$z = $p^$i";
return 1;
}
}
return 0;
}
Similarly, using php's built in log function. But it may not be as accurate (if there are rounding errors, false positives may occur).
function check($z) {
for($p = 2; $p < sqrt($z); $p++) {
$q = log($z,$p);
if($q == round($q)) {
return 1;
}
}
return 0;
}
How can I calculate the n-th root of an integer using PHP/GMP?
Although I found a function called gmp_root(a, nth) in the PHP source, it seems that this function has not been published in any release yet*: http://3v4l.org/8FjU7
*) 5.6.0alpha2 being the most recent one at the time of writing
Original source: Calculating Nth root with bcmath in PHP – thanks and credits to HamZa!
I've rewritten the code to use GMP instead of BCMath:
function gmp_nth_root($num, $n) {
if ($n < 1) return 0; // we want positive exponents
if ($num <= 0) return 0; // we want positive numbers
if ($num < 2) return 1; // n-th root of 1 or 2 give 1
// g is our guess number
$g = 2;
// while (g^n < num) g=g*2
while (gmp_cmp(gmp_pow($g, $n), $num) < 0) {
$g = gmp_mul($g, 2);
}
// if (g^n==num) num is a power of 2, we're lucky, end of job
if (gmp_cmp(gmp_pow($g, $n), $num) == 0) {
return $g;
}
// if we're here num wasn't a power of 2 :(
$og = $g; // og means original guess and here is our upper bound
$g = gmp_div($g, 2); // g is set to be our lower bound
$step = gmp_div(gmp_sub($og, $g), 2); // step is the half of upper bound - lower bound
$g = gmp_add($g, $step); // we start at lower bound + step , basically in the middle of our interval
// while step != 1
while (gmp_cmp($step, 1) > 0) {
$guess = gmp_pow($g, $n);
$step = gmp_div($step, 2);
$comp = gmp_cmp($guess, $num); // compare our guess with real number
if ($comp < 0) { // if guess is lower we add the new step
$g = gmp_add($g, $step);
} else if ($comp == 1) { // if guess is higher we sub the new step
$g = gmp_sub($g, $step);
} else { // if guess is exactly the num we're done, we return the value
return $g;
}
}
// whatever happened, g is the closest guess we can make so return it
return $g;
}
Does anybody know a PHP function for IMEI validation?
Short solution
You can use this (witchcraft!) solution, and simply check the string length:
function is_luhn($n) {
$str = '';
foreach (str_split(strrev((string) $n)) as $i => $d) {
$str .= $i %2 !== 0 ? $d * 2 : $d;
}
return array_sum(str_split($str)) % 10 === 0;
}
function is_imei($n){
return is_luhn($n) && strlen($n) == 15;
}
Detailed solution
Here's my original function that explains each step:
function is_imei($imei){
// Should be 15 digits
if(strlen($imei) != 15 || !ctype_digit($imei))
return false;
// Get digits
$digits = str_split($imei);
// Remove last digit, and store it
$imei_last = array_pop($digits);
// Create log
$log = array();
// Loop through digits
foreach($digits as $key => $n){
// If key is odd, then count is even
if($key & 1){
// Get double digits
$double = str_split($n * 2);
// Sum double digits
$n = array_sum($double);
}
// Append log
$log[] = $n;
}
// Sum log & multiply by 9
$sum = array_sum($log) * 9;
// Compare the last digit with $imei_last
return substr($sum, -1) == $imei_last;
}
Maybe can help you :
This IMEI number is something like this: ABCDEF-GH-IJKLMNO-X (without “-” characters)
For example: 350077523237513
In our example ABCDEF-GH-IJKLMNO-X:
AB is Reporting Body Identifier such as 35 = “British Approvals Board of Telecommunications (BABT)”
ABCDEF is Type Approval Code
GH is Final Assembly Code
IJKLMNO is Serial Number
X is Check Digit
Also this can help you : http://en.wikipedia.org/wiki/IMEI#Check_digit_computation
If i don't misunderstood, IMEI numbers using Luhn algorithm . So you can google this :) Or you can search IMEI algorithm
Maybe your good with the imei validator in the comments here:
http://www.php.net/manual/en/function.ctype-digit.php#77718
But I haven't tested it
Check this solution
<?php
function validate_imei($imei)
{
if (!preg_match('/^[0-9]{15}$/', $imei)) return false;
$sum = 0;
for ($i = 0; $i < 14; $i++)
{
$num = $imei[$i];
if (($i % 2) != 0)
{
$num = $imei[$i] * 2;
if ($num > 9)
{
$num = (string) $num;
$num = $num[0] + $num[1];
}
}
$sum += $num;
}
if ((($sum + $imei[14]) % 10) != 0) return false;
return true;
}
$imei = '868932036356090';
var_dump(validate_imei($imei));
?>
IMEI validation uses Luhn check algorithm. I found a link to a page where you can validate your IMEI. Furthermore, at the bottom of this page is a piece of code written in JavaScript to show how to calculate the 15th digit of IMEI and to valid IMEI. I might give you some ideas. You can check it out here http://imei.sms.eu.sk/index.html
Here is a jQuery solution which may be of use: https://github.com/madeinstefano/imei-validator
good fun from kasperhartwich
function validateImei($imei, $use_checksum = true) {
if (is_string($imei)) {
if (ereg('^[0-9]{15}$', $imei)) {
if (!$use_checksum) return true;
for ($i = 0, $sum = 0; $i < 14; $i++) {
$tmp = $imei[$i] * (($i%2) + 1 );
$sum += ($tmp%10) + intval($tmp/10);
}
return (((10 - ($sum%10)) %10) == $imei[14]);
}
}
return false;
}