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.
Related
I would like to use base_convert function to convert 60 bit binary data to Hex code as follows. But the result is not correct. The output of the code below is 4e08556312ffc00 but the correct output is 4E08556312FFBFF.
Can anybody tell me why? is 60 bit too large to the function?
echo "The beacon ID in Hexadecimal is".base_convert
("010011100000100001010101011000110001001011111111101111111111",2, 16);
Thank
I have posted an implementation of a base conversion function without such limits in my answer to another question here.
According to base_convert and floating numbers documentation, base_convert will lose precision on large numbers.
Instead of, you can use bin2hex, which is not limited (this function use and return strings)
My tests reveal a loss of precision over 43bits.
I work on a Win XP base + easyphp 3.1.81 with default settings.
I use this base_convert for a genealogical application, and the limit of 43 generations is - sometimes - not enough.
It is the larger of:
PHP_INT_MAX and
The maximum of the contiguous set of integers that can be expressed as a float.
Typical PHP implementations use IEEE 754 for implementing floating point numbers, which has a 53-bit significand, so the typical limit for 32-bit environments is 2⁵³ (0x20000000000000) and for 64-bit environments, the limit is 2⁶³-1 (0x7fffffffffffffff).
There’s a trivial solution if you have the PHP gmp extension ( http://php.net/gmp ):
$hexNumber = gmp_strval( gmp_init( $binNumber, 2 ), 16 ) ;
If you have the bc extension (http://php.net/bc ), my (free & open source) WeirdoCustomDigits module will do conversions with arbitrary bases and arbitrary digit characters, without limitation.
If you're simply converting between base 2 and base 16, as with your example, you can get by without bc or gmp. See the source in the WeirdoCustomDigits module for WeirdoCustomDigits::binFromHex() and WeirdoCustomDigits::hexFromBin().
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 :)
Let's say I have:
echo 1/3;
And it print out only 0.33333333333333, can I get more digits?
Can use bcdiv
echo bcdiv(1, 3, 20);
The third argument
is used to set the number of digits after the decimal place in the result. You can also set the global default scale for all functions by using bcscale().
Edit the precision configuration variable either in your php.ini or some other configuration location or use ini_set().
ini_set('precision', 22);
echo 1/3;
// 0.3333333333333333148296
Even though I highly doubt that you really need that kind of precision ;-)
EDIT
As Gordon said: you'll hit the floating point precision limit in PHP sooner or later (depending on the precision specified). So the better way would be to use either the BCMath Arbitrary Precision Mathematics extension or the GNU Multiple Precision extension, if you're after real high precision mathematics.
You might want tto look into the BC arbitary precision php library
http://php.net/manual/en/book.bc.php
The setting is precision: http://es.php.net/manual/en/ini.core.php
However, I would not use it except for debugging purposes. Have a look at number_format()
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, ...
I found some solution Efficient way of doing 64 bit rotate using 32 bit values but it's not in PHP.
The biggest problem is that I get from remote server big integer 9223372036854775808(10) as hexadecimal 8000000000000000(16).
There is no chance to enable php_gmp (extension) on production server but I have to check selected bits in received value. Both, production and development server are 32bits machines.
You can accomplish this using BC Math (Arbitrary Precision Mathematics):
BC Math allows you to perform mathematic operations on numbers. The difference between using arithmetic operators and using BC Maths is that instead of storing the number as an integer or a float, BC Math returns the number as string.
http://php.net/manual/en/ref.bc.php
PHP has to be compiled with BC Math; however most PHP installs should have this.
Unfortunately you can't do bitwise operations on strings, and BC Math doesn't have any built-in bitwise functions. However; after doing a bit of Googling, I found the following code sample and I've copied and pasted it here below:
function bitValue($no) { return bcpow(2, $no); }
function bitSet($no, $value) {
$tmp = bcmod($value, bitValue($no+1));
return bccomp(bcsub($tmp, bitValue($no)), 0)>= 0;
}
echo bitSet(49, bitValue(48)) ."\n";
echo bitSet(48, bitValue(48)) ."\n";
echo bitSet(47, bitValue(48)) ."\n";
(Credits to hernst42)