How do I go about converting a math equation into php? - 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.

Related

PHP SourceCode Random

The function for rand() should be something like (SEED * A + C) mod M.
How can I find the values of A, C, and M? And if I find those values, can I predict the next number in the sequence?
I know that I can find the values of these variables in the PHP source code. But after looking around I really cannot find them...
Does anybody know what file it would be in? Or who else I could contact (I've tried email internals#lists.php.net but haven't got a response)
Also I'm doing all this in PHP versions prior to 7, where rand() and mt_rand() became synonymous.
EDIT: I have seen Is it possible to predict rand(0,10) in PHP? but those answers aren't about the constant values in PHP's rand() value by themselves.
Thank you!
I believe that the old school rand() function used a linear congruential generator.
This generator is system dependent. One algorithm employed by glibc was:
next = next * 1103515245 + 12345;
return next & 0x7fffffff;
so there you have your constants. The state, of course, is the initial value of 'next', which is zero unless set differently by srand().
There are ways of attacking a linear congruence; one possibility - the slowest, but the easiest to explain - is to brute force it. Say that you four consecutive values: a0, a1, a2, a3 from your rand() implementation. You can check all values of seed that would yield that same sequence.
Note that if your a0 value is produced by, say, rand() % 7172, then your initial seed must obey the rule that "seed % 7172 === a0". This immediately reduces the space you need to brute force, speeding up operations proportionately. Also, you don't need to check all four numbers.
This would be the efficient equivalent of running (in PHP)
for ($seed = 0; $seed < MAX_SEED; $seed++) {
srand($seed);
if ($a0 !== [RAND() FORMULA]) return false;
if ($a1 !== [RAND() FORMULA]) return false;
if ($a2 !== [RAND() FORMULA]) return false;
if ($a3 !== [RAND() FORMULA]) return false;
return true;
}
Experiments
By checking with a reference trivial C source code
#include <stdio.h>
int main() {
srand(1);
printf("%ld\n", rand());
}
I determined that PHP and C do indeed share the same underlying function (I tabulated different values for srand()).
I also found out that srand(0) and srand(1) yield the same result, which isn't consistent with my linear model.
And that's because glibc rand() is not so trivial a linear congruential generator. More info here. Actually it is quoted in a SO answer and the code I had was for the old, TYPE_0 generator.

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.

Create indexable non-repeating combinations with fixed length

Based on this question
Ordered Fixed Length Combination of a String
I created a PHP algorithm that creates combinations of characters on a fixed length (basically a rewrite of the Java-answer)
private function getCombination($length, $input) {
$result = array();
if ($length == 0) {
return $result;
}
$first = substr($input, 0, $length);
$result[] = $first;
if (strlen($input) == $length) {
return $result;
}
$tails = $this->getCombination($length - 1, substr($input, 1));
foreach ($tails as $tail) {
$tmp = substr($input, 0, 1) . $tail;
if (!in_array($tmp, $result)) {
$result[] = $tmp;
}
}
return array_merge($result, $this->getCombination($length, substr($input, 1)));
}
For another question, Create fixed length non-repeating permutation of larger set, I was given a (brilliant) algorithm that would make permutations indexable, effectively making them adressable by providing a "key" that would always produce the exact same permutation, when given the same set of characters and the same length.
Well, now I basically need the same but for combinations, in contrast to permutations as in my other question.
Can the algorithm above be modified in the same way? Meaning to create a function like
public function getCombinationByIndex($length, $index);
That will return one combination out of the thousand possible that is created with the algorithm without creating them beforehand?
I have written a class in C# to handle common functions for working with the binomial coefficient, which is the type of problem that your problem appears to fall under - assuming that you working with combinations instead of permutations. It performs the following tasks:
Outputs all the K-indexes in a nice format for any N choose K to a file. The K-indexes can be substituted with more descriptive strings or letters.
Converts the K-indexes to the proper index of an entry in the sorted binomial coefficient table. This technique is much faster than older published techniques that rely on iteration. It does this by using a mathematical property inherent in Pascal's Triangle.
Converts the index in a sorted binomial coefficient table to the corresponding K-indexes. I believe it is also faster than older iterative solutions.
Uses Mark Dominus method to calculate the binomial coefficient, which is much less likely to overflow and works with larger numbers.
The class is written in .NET C# and provides a way to manage the objects related to the problem (if any) by using a generic list. The constructor of this class takes a bool value called InitTable that when true will create a generic list to hold the objects to be managed. If this value is false, then it will not create the table. The table does not need to be created in order to use the 4 above methods. Accessor methods are provided to access the table.
There is an associated test class which shows how to use the class and its methods. It has been extensively tested with 2 cases and there are no known bugs.
To read about this class and download the code, see Tablizing The Binomial Coeffieicent.
It should be pretty straight forward to port this class over to php. You probably will not have to port over the generic part of the class to accomplish your goals. Denending on the number of combinations you are working with, you might need to use a bigger word size than 4 byte ints.

Power function in php to calculate 17^2147482999

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 :)

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, ...

Categories