1

I've looked at php-big numbers, BC Math, and GMP for dealing with very big numbers in php. But none seem to have a function equivilent to php's log(). For example I want to do this:

$result = log($bigNumber, 2);

Would anyone know of an alternate way to get the log base 2 of a arbitray precision point number in php? Maybe Ive missed a function, or library, or formula.

edit: php-bignumbers seems to have a log base 10 function only log10()

Andrew
  • 18,680
  • 13
  • 103
  • 118
  • May not be a duplicate, but very close to this: http://stackoverflow.com/questions/8232932/logarithm-of-the-very-very-large-number – James Black Jun 16 '14 at 02:08
  • 1
    Log works with big numbers, but it loses precision. – sectus Jun 16 '14 at 02:20
  • Anyway logarithm could return irrational number. And you cannot work with exact precision numbers while working with log and arbitrary numbers. You have to be more specific. – sectus Jun 16 '14 at 03:12

4 Answers4

3

In general if you want to implement your high precision log own calculation, I'd suggest 1st use the basic features of logarithm:

log_a(x) = log_b(x) / log_b(a) |=> thus you can recalulate logarith to any base
log(x*y) = log(x) + log(y)
log(a**n) = n*log(a)

where log_a(x) - meaning logarithm to the base a of x; log means natural logarithm

So log(1000000000000000000000.123) = 21*log(1.000000000000000000000123)

and for high precision of log(1+x) use algorithm referenced at http://en.wikipedia.org/wiki/Natural_logarithm#High_precision

agamike
  • 479
  • 3
  • 5
  • 1
    The first property should be all you need to implement a `bignum` version of `log2` : `log2($num) = log10($num) / log10(2);` – Floris Jun 16 '14 at 04:54
1

One solution combining the suggestions so far would be to use this formula:

log2($num) = log10($num) / log10(2)

in conjunction with php-big numbers since it has a pre-made log10 function.

eg, after installing the php-big numbers library, use:

$log2 = log10($bigNum) / log10(2);

Personally I've decided to use different math/logic so as to not need the log function, and just using bcmath for the big numbers.

Andrew
  • 18,680
  • 13
  • 103
  • 118
1

One of the great things about base 2 is that counting and shifting become part of the tool set.

So one way to get a 'log2' of a number is to convert it to a binary string and count the bits.

You can accomplish this equivalently by dividing by 2 in a loop. But it seems to me that counting would be more efficient.

gmp_scan0 and gmp_scan1 can be used if you are counting from the right. But you'd have to somehow convert the mixed bits to all ones and zeroes.

But using gmp_strval(num, 2), you can produce a string and do a strpos on it.

if the whole value is being converted, you can do a (strlen - 1) on it.

Obviously this only works when you want an integer log.

Gerard ONeill
  • 3,914
  • 39
  • 25
1

I've had a very similar problem just recently.. and so I just scaled the number considerably in order to use the inbuild log to find the fractional part.. (I prefere the log10 for some reason.. don't ask... people are strange, me too) I hope this is selfexplanatory enough.. it returns a float value (since that's what I needed)

function gmp_log($num, $base=10, $full=true)
{
    if($base == 10)
        $string = gmp_strval($num);
    else
        $string = gmp_strval($num,$base);

    $intpart = strlen($string)-1;

    if(!$full)
        return $intpart;

    if($base ==10)
    {
        $string = substr_replace($string, ".", 1, 0);
        $number = floatval($string);
        $lg = $intpart + log10($number);
        return $lg;
    }
    else
    {
        $string = gmp_strval($num);
        $intpart = strlen($string)-1;
        $string = substr_replace($string, ".", 1, 0);
        $number = floatval($string);
        $lg = $intpart + log10($number);

        $lb = $lg / log10($base);
        return $lb;
    }
}

it's quick, it's dirty... but it works well enough to get the log of some RSA sized integers ;)

usage is straight forward as well

$N = gmp_init("11002930366353704069");
echo gmp_log($N,10)."\n";
echo gmp_log($N,10, false)."\n";
echo gmp_log($N,2)."\n";
echo gmp_log($N,16)."\n";

returns

19.041508364472 
19 
63.254521604973 
15.813630401243
itsid
  • 801
  • 7
  • 16
  • Exactly what I was looking for! I had to change line `$intpart = strlen($string)-1;` to `$intpart = strlen($string);` though to get the correct result. Therefore I never verified all the code after that line and never know if it's working well. – David Jul 13 '21 at 05:10