Power function in php to calculate 17^2147482999 - php

I am trying to make a power function to calculate the power of 17^2147482999.
I tried this code:
function ipow($a, $b) {
if ($b<0) {
echo "B must be a positive integer";
}
if ($b==0) return 1;
if ($a==0) return 0;
if ($b%2==0) {
return ipow($a*$a, $b/2);
} else if ($b%2==1) {
return $a*ipow($a*$a,$b/2);
}
return 0;
}
The function call:
echo ipow($a, $b);
The error:
Fatal error: Maximum function nesting level of '100' reached, aborting! in C:\wamp\www\spoj\LASTDIG.php on line 23
Is there any other way to calculate the power for such big values? The inbuilt pow() function is giving an INF output.
UPDATE
If it seems impossible to get the whole answer, is it possible to extract atleast the last 5-10 digits of the answer by some mathematical approach?

You cannot do that with plain PHP arithemtic operations. That's way out of range for integers, even on 64-bit systems.
You need to use the bcmath extension and the bcpow function. (If that doesn't work maybe even gmp.)
print bcpow(17, 2147482999);

You may use bcpowmod function like this:
<?php echo bcpowmod(17,2147482999,10000000000); ?>
the result is 8849802353 which means, 17^2147482999 mod 10000000000 or, the last 10 digits of 17^2147482999 is 8849802353.

The resulting value is something in the order of 1e+2642368139, a lot more than can fit in most libraries. If you want some approximation, you can use some logarithmic logic:
17^2147482999 = 10^(log(17^2147482999))
= 10^(2147482999 * log(17))
= 10^(2147482999 * 1.23045)
= 10^(2642368139.79773)
= 10^2642368139 * 10^0.79773
= 6.27669e+2642368139

GNU Multiple Precision and namely gmp_pow may be what you are looking for.

I suggest you look into BigInteger, the constant PHP_INT_MAX will tell you how big an integer your platform can handle. On 64 bit this returns 9223372036854775807, wich is far from for your result in decimal notation.

Try to change the algorithm and instead of working with numbers (as the data type) ... work with plain strings. It will take a lot of time to compute it but it will be achievable :)

Related

php power of number mod number not work

why this function return 0 ?
public function encrypt(){
return (pow(123,17)%3233);
}
What happens here is you get an integer overflow. Your number is way bigger than PHP_INT_MAX. So to still be able to do this calculation you can use the BC math library .
So just use bcpowmod(), e.g.
echo bcpowmod(123, 17, 3233);

How do I go about converting a math equation into php?

I am not so good at maths and I'm looking to transfer 3 math equations to php functions.
I've tried looking up how to individually do each part of the equation in php but I keep getting strange results so I must be doing something wrong.
Is there a php function for exponential growth?
The image with the equations are here:
http://i.imgur.com/zIhMEEu.jpg
Thanks
For the second equation this is what I have:
$rank = 50;
$xp = log(24000 * (2^($rank/6) - 1));
echo $xp;
The number is too small for this to be correct. I'm also not sure how to convert the 'ln 2' into PHP. The log() function seemed to come up under 'natural logarithm to php' search.
There are various functions that need to be combined in order to create these equations. The log function performs logarithm operations in a base of your choice (or ln if you do not provide a base). The pow function performs exponentiation.
Your equations would be:
function rank($xp) {
return floor(6 * log((xp * log(2) / 24000 + 1), 2));
}
function xp($rank) {
return floor(24000 * (pow(2, (rank / 6)) - 1) / log(2));
}
function kills($rank) {
return floor(xp($rank) / 200);
}
There are a few more parentheses there than absolutely needed, for clarity's sake.
Mathematical notations in general are considerably more compact and expressive than most programming languages (not just PHP) due to the fact that you can use any symbol you can think of to represent various concepts. In programming, you're stuck calling functions.
Also, I'm not sure what the various hardcoded numbers represent, or if it makes sense to change them, in the context of the formula, but you might want to think about setting them up as extra parameters to the function. For example:
function kills($rank, $killsPerXp = 200) {
return floor(xp($rank) / $killsPerXp);
}
This adds clarity to the code, because it lets you know what the numbers represent. At the same time, it allows you to change the numbers more easily in case you are using them in multiple places.

PHP's pow() with a negative number as input doesn't work

PHP's pow() doesn't want to process the following:
pow(-5,1/3);
While in fact it is supposed to work. How can I do this in PHP?
You are basically taking the 3rd root of a negative number here.
This is not always possible in the real number space. So in some cases you would need an imaginary unit to solve that equation.
It seems as if php just outputs NAN for cases where the base is negative and the exponent < 1.
As PeeHaa has pointed out, the docs state that for some exponents the results can be "weird".
Algebraically the following is valid:
-x^(p) == -1*(x^p)
You could use this as a workaround. Speaking in code:
$x = pow(5,1/3)*-1;
But be wary of exponents like n/m with m being an even number!
You could use the following function to cover that as well:
function real_pow($base, $exponent){
if($base < 0){
if($exponent >= 1) return pow($base * -1, $exponent) * -1;
else{
if(is_nan(pow($base, $exponent))) return false;
else return pow($base, $exponent);
}
}else{
return pow($base, $exponent);
}
}
This function will return valid pow's if the result is not a complex number. If it is, it will return false.
Mathematically -51/3 is defined as simply the cube root of -5, which is around -1.71.
However, there's no way to precisely represent 1/3 in floating point. So, you're asking PHP to calculate something like -50.33333333333333331482961.
Now, if that exponent's exact rational expansion has an even denominator, the result is purely imaginary. If the exact rational expansion has an odd denominator, the result is purely real. The problem is that it is impossible to determine whether the denominator is "even" or "odd" because of the inadequate precision.
So, PHP doesn't bother. It just tells you that you can't do it, and that's the end of the story.
$base=-5;
$exponent=1/3;
$result = ($base<0?-1:1)*pow(abs($base),$exponent);
It is not valid for exponents being rationals with even denominator because it produces a complex number which PHP does not handle. You can write your own class/functions or google it, there are some in the web, but I never tested.

How to compare two 64 bit numbers

In PHP I have a 64 bit number which represents tasks that must be completed. A second 64 bit number represents the tasks which have been completed:
$pack_code = 1001111100100000000000000011111101001111100100000000000000011111
$veri_code = 0000000000000000000000000001110000000000000000000000000000111110
I need to compare the two and provide a percentage of tasks completed figure. I could loop through both and find how many bits are set, but I don't know if this is the fastest way?
Assuming that these are actually strings, perhaps something like:
$pack_code = '1001111100100000000000000011111101001111100100000000000000011111';
$veri_code = '0000000000000000000000000001110000000000000000000000000000111110';
$matches = array_intersect_assoc(str_split($pack_code),str_split($veri_code));
$finished_matches = array_intersect($matches,array(1));
$percentage = (count($finished_matches) / 64) * 100
Because you're getting the numbers as hex strings instead of ones and zeros, you'll need to do a bit of extra work.
PHP does not reliably support numbers over 32 bits as integers. 64-bit support requires being compiled and running on a 64-bit machine. This means that attempts to represent a 64-bit integer may fail depending on your environment. For this reason, it will be important to ensure that PHP only ever deals with these numbers as strings. This won't be hard, as hex strings coming out of the database will be, well, strings, not ints.
There are a few options here. The first would be using the GMP extension's gmp_xor function, which performs a bitwise-XOR operation on two numbers. The resulting number will have bits turned on when the two numbers have opposing bits in that location, and off when the two numbers have identical bits in that location. Then it's just a matter of counting the bits to get the remaining task count.
Another option would be transforming the number-as-a-string into a string of ones and zeros, as you've represented in your question. If you have GMP, you can use gmp_init to read it as a base-16 number, and use gmp_strval to return it as a base-2 number.
If you don't have GMP, this function provided in another answer (scroll to "Step 2") can accurately transform a string-as-number into anything between base-2 and 36. It will be slower than using GMP.
In both of these cases, you'd end up with a string of ones and zeros and can use code like that posted by #Mark Baker to get the difference.
Optimization in this case is not worth of considering. I'm 100% sure that you don't really care whether your scrip will be generated 0.00000014 sec. faster, am I right?
Just loop through each bit of that number, compare it with another and you're done.
Remember words of Donald Knuth:
We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.
This code utilizes the GNU Multi Precision library, which is supported by PHP, and since it is implemented in C, should be fast enough, and supports arbitrary precision.
$pack_code = gmp_init("1001111100100000000000000011111101001111100100000000000000011111", 2);
$veri_code = gmp_init("0000000000000000000000000001110000000000000000000000000000111110", 2);
$number_of_different_bits = gmp_popcount(gmp_xor($pack_code, $veri_code));
$a = 11111;
echo sprintf('%032b',$a)."\n";
$b = 12345;
echo sprintf('%032b',$b)."\n";
$c = $a & $b;
echo sprintf('%032b',$c)."\n";
$n=0;
while($c)
{
$n += $c & 1;
$c = $c >> 1;
}
echo $n."\n";
Output:
00000000000000000010101101100111
00000000000000000011000000111001
00000000000000000010000000100001
3
Given your PHP-setuo can handle 64bit, this can be easily extended.
If not you can sidestep this restriction using GNU Multiple Precision
You could also split up the HEx-Representation and then operate on those coresponding parts parts instead. As you need just the local fact of 1 or 0 and not which number actually is represented! I think that would solve your problem best.
For example:
0xF1A35C and 0xD546C1
you just compare the binary version of F and D, 1 and 5, A and 4, ...

Factorial of 170+

everytime I try to get the factorial of 171, I get INF. 170 works fine. Is it possible to get the factorial of 171+ in a script? How?
My function:
function factorial($n) {
if ($n == 0) return 1;
return $n * factorial($n - 1);
}
If you deal with very large numbers, you'll need to use an extension that allows you to do that.
There's BCMath ( http://www.php.net/manual/en/book.bc.php) , and GMP ( http://www.php.net/manual/en/book.gmp.php ).
You'll have to use BC Math or GNU MP extension. PHP doesn't provide any tools for high-values or high-precision operations OOTB.
echo "1241018070217667823424840524103103992616605577501693185388951803611996075221691752992751978120487585576464959501670387052809889858690710767331242032218484364310473577889968548278290754541561964852153468318044293239598173696899657235903947616152278558180061176365108428800000000000000000000000000000000000000000"
really though, your function is fine. I think PHP lacks that kind of precision. I got the value (it is correct btw) in python
You are probably getting a value that exceeds the maximum double precision float in a 32-bit machine (~10^308). 170! factorial is ~7.25741562 × 10^307 which is just under that, however, 171! is larger. Your best bet is to use one of the libraries EboMike or Crozin recommends in their answers.
For large n, you can compute n! very quickly with little error using Stirling's approximation. Take a look at this post; it has an analysis of the function and some sample code:
http://threebrothers.org/brendan/blog/stirlings-approximation-formula-clojure/
It's a bigger number than you can hold using 32-bits. If you run the same code on a 64-bit computer then it should work.

Categories