mirror of
https://github.com/phpseclib/phpseclib.git
synced 2025-02-05 13:28:27 +00:00
a few changes to danog's changes
This commit is contained in:
parent
7cf300984c
commit
72d1bdf60b
@ -3699,13 +3699,17 @@ class BigInteger
|
|||||||
*/
|
*/
|
||||||
function root($n = null)
|
function root($n = null)
|
||||||
{
|
{
|
||||||
|
static $zero, $one, $two;
|
||||||
|
if (!isset($one)) {
|
||||||
|
$zero = new static(0);
|
||||||
$one = new static(1);
|
$one = new static(1);
|
||||||
$two = new static(2);
|
$two = new static(2);
|
||||||
|
}
|
||||||
if ($n === null) {
|
if ($n === null) {
|
||||||
$n = $two;
|
$n = $two;
|
||||||
}
|
}
|
||||||
if ($n->compare($one) == -1) {
|
if ($n->compare($one) == -1) {
|
||||||
return new static(0);
|
return $zero;
|
||||||
} // we want positive exponents
|
} // we want positive exponents
|
||||||
if ($this->compare($one) == -1) {
|
if ($this->compare($one) == -1) {
|
||||||
return new static(0);
|
return new static(0);
|
||||||
@ -3713,52 +3717,13 @@ class BigInteger
|
|||||||
if ($this->compare($two) == -1) {
|
if ($this->compare($two) == -1) {
|
||||||
return $one;
|
return $one;
|
||||||
} // n-th root of 1 or 2 is 1
|
} // n-th root of 1 or 2 is 1
|
||||||
|
|
||||||
$root = new static();
|
$root = new static();
|
||||||
switch (MATH_BIGINTEGER_MODE) {
|
if (MATH_BIGINTEGER_MODE == self::MODE_GMP && function_exists('gmp_root')) {
|
||||||
case self::MODE_BCMATH:
|
|
||||||
// g is our guess number
|
|
||||||
$g = 2;
|
|
||||||
// while (g^n < num) g=g*2
|
|
||||||
while (bccomp(bcpow($g, $n->value), $this->value) == -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->value), $this->value) == 0) {
|
|
||||||
$root->value = $g;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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, $this->value); // compare our guess with real number
|
|
||||||
if ($comp == -1) { // if guess is lower we add the new step
|
|
||||||
$g = bcadd($g, $step);
|
|
||||||
} elseif ($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
|
|
||||||
$root->value = $g;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// whatever happened, g is the closest guess we can make so return it
|
|
||||||
$root->value = $g;
|
|
||||||
break;
|
|
||||||
case self::MODE_GMP:
|
|
||||||
if (function_exists('gmp_root')) {
|
|
||||||
$root->value = gmp_root($this->value, gmp_intval($n->value));
|
$root->value = gmp_root($this->value, gmp_intval($n->value));
|
||||||
break;
|
return $this->_normalize($root);
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
// g is our guess number
|
// g is our guess number
|
||||||
$g = $two;
|
$g = $two;
|
||||||
// while (g^n < num) g=g*2
|
// while (g^n < num) g=g*2
|
||||||
@ -3769,7 +3734,7 @@ class BigInteger
|
|||||||
// == 0 bccomp(bcpow($g,$n), $n->value)==0
|
// == 0 bccomp(bcpow($g,$n), $n->value)==0
|
||||||
if ($g->pow($n)->equals($this)) {
|
if ($g->pow($n)->equals($this)) {
|
||||||
$root = $g;
|
$root = $g;
|
||||||
break;
|
return $this->_normalize($root);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we're here num wasn't a power of 2 :(
|
// if we're here num wasn't a power of 2 :(
|
||||||
@ -3778,26 +3743,31 @@ class BigInteger
|
|||||||
$step = $og->subtract($g)->divide($two)[0]; // step is the half of upper bound - lower bound
|
$step = $og->subtract($g)->divide($two)[0]; // step is the half of upper bound - lower bound
|
||||||
$g = $g->add($step); // we start at lower bound + step , basically in the middle of our interval
|
$g = $g->add($step); // we start at lower bound + step , basically in the middle of our interval
|
||||||
|
|
||||||
// while step!=1
|
// while step>1
|
||||||
|
|
||||||
while ($step->compare($one) == 1) {
|
while ($step->compare($one) == 1) {
|
||||||
$guess = $g->pow($n);
|
$guess = $g->pow($n);
|
||||||
$step = $step->divide($two)[0];
|
$step = $step->divide($two)[0];
|
||||||
$comp = $guess->compare($this); // compare our guess with real number
|
$comp = $guess->compare($this); // compare our guess with real number
|
||||||
if ($comp == -1) { // if guess is lower we add the new step
|
switch ($comp) {
|
||||||
|
case -1: // if guess is lower we add the new step
|
||||||
$g = $g->add($step);
|
$g = $g->add($step);
|
||||||
} elseif ($comp == 1) { // if guess is higher we sub the new step
|
|
||||||
$g = $g->subtract($step);
|
|
||||||
} else { // if guess is exactly the num we're done, we return the value
|
|
||||||
$root = $g;
|
|
||||||
break;
|
break;
|
||||||
|
case 1: // if guess is higher we sub the new step
|
||||||
|
$g = $g->subtract($step);
|
||||||
|
break;
|
||||||
|
case 0: // if guess is exactly the num we're done, we return the value
|
||||||
|
$root = $g;
|
||||||
|
break 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($comp == 1) {
|
||||||
|
$g = $g->subtract($step);
|
||||||
|
}
|
||||||
|
|
||||||
// whatever happened, g is the closest guess we can make so return it
|
// whatever happened, g is the closest guess we can make so return it
|
||||||
$root = $g;
|
$root = $g;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->_normalize($root);
|
return $this->_normalize($root);
|
||||||
}
|
}
|
||||||
@ -3805,7 +3775,6 @@ class BigInteger
|
|||||||
/**
|
/**
|
||||||
* Performs exponentiation.
|
* Performs exponentiation.
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* @param \phpseclib\Math\BigInteger $n
|
* @param \phpseclib\Math\BigInteger $n
|
||||||
* @access public
|
* @access public
|
||||||
* @return \phpseclib\Math\BigInteger
|
* @return \phpseclib\Math\BigInteger
|
||||||
@ -3836,69 +3805,74 @@ class BigInteger
|
|||||||
}
|
}
|
||||||
|
|
||||||
return $res;
|
return $res;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the minimum BigInteger between two BigIntegers.
|
* Return the minimum BigInteger between an arbitrary number of BigIntegers.
|
||||||
*
|
*
|
||||||
*
|
* @param \phpseclib\Math\BigInteger ...$param
|
||||||
* @param \phpseclib\Math\BigInteger $a
|
|
||||||
* @param \phpseclib\Math\BigInteger $b
|
|
||||||
* @access public
|
* @access public
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return \phpseclib\Math\BigInteger
|
* @return \phpseclib\Math\BigInteger
|
||||||
*/
|
*/
|
||||||
function min($b)
|
static function min()
|
||||||
{
|
{
|
||||||
if ($this->compare($b) == '1') {
|
$args = func_get_args();
|
||||||
return $b;
|
if (count($args) == 1) {
|
||||||
|
return $args[0];
|
||||||
}
|
}
|
||||||
|
$min = $args[0];
|
||||||
return $this;
|
for ($i = 1; $i < count($args); $i++) {
|
||||||
|
$min = $min->compare($args[$i]) > 0 ? $args[$i] : $min;
|
||||||
|
}
|
||||||
|
return $min;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the maximum BigInteger between two BigIntegers.
|
* Return the maximum BigInteger between an arbitrary number of BigIntegers.
|
||||||
*
|
*
|
||||||
*
|
* @param \phpseclib\Math\BigInteger ...$param
|
||||||
* @param \phpseclib\Math\BigInteger $b
|
|
||||||
* @access public
|
* @access public
|
||||||
*
|
|
||||||
* @return \phpseclib\Math\BigInteger
|
* @return \phpseclib\Math\BigInteger
|
||||||
*/
|
*/
|
||||||
function max($b)
|
static function max()
|
||||||
{
|
{
|
||||||
if ($this->compare($b) == '1') {
|
$args = func_get_args();
|
||||||
return $this;
|
if (count($args) == 1) {
|
||||||
|
return $args[0];
|
||||||
}
|
}
|
||||||
|
$max = $args[0];
|
||||||
return $b;
|
for ($i = 1; $i < count($args); $i++) {
|
||||||
|
$max = $max->compare($args[$i]) < 0 ? $args[$i] : $max;
|
||||||
|
}
|
||||||
|
return $max;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute a function n times, where n is the current BigInteger.
|
* Execute a function n times, where n is the current BigInteger.
|
||||||
* The passed function must accept a paremeter that will be set to the the current number
|
* The passed function must accept a parameter that will be set to the the current number
|
||||||
* (that number will range from zero to BigInteger - 1 if the BigInteger is positive, and from BigInteger - 1 to zero if the BigInteger is negative).
|
* (that number will range from zero to BigInteger - 1 if the BigInteger is positive, and from BigInteger - 1 to zero if the BigInteger is negative).
|
||||||
* You can also set it to accept an optional parameter, that will be equal to the optional $userdata parameter.
|
* You can also set it to accept an optional parameter, that will be equal to the optional $userdata parameter.
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param callable $function
|
* @param callable $function
|
||||||
* @param &$userdata
|
* @param &$userdata
|
||||||
*
|
|
||||||
* @return \phpseclib\Math\BigInteger
|
* @return \phpseclib\Math\BigInteger
|
||||||
*/
|
*/
|
||||||
function loopforeach(callable $function, &$userdata = null)
|
function loopforeach(callable $function, &$userdata = null)
|
||||||
{
|
{
|
||||||
if ($this->compare(new static(0)) < 0) { // negative
|
static $zero;
|
||||||
|
if (!isset($zero)) {
|
||||||
|
$zero = new static(0);
|
||||||
|
}
|
||||||
|
if ($this->compare($zero) < 0) { // negative
|
||||||
$limit = new static(-PHP_INT_MAX - 1);
|
$limit = new static(-PHP_INT_MAX - 1);
|
||||||
$one = new static(-1);
|
$one = new static(-1);
|
||||||
} else { // positive
|
} else { // positive
|
||||||
$limit = new static(PHP_INT_MAX);
|
$limit = new static(PHP_INT_MAX);
|
||||||
$one = new static(1);
|
$one = new static(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->compare($limit) == -((int) $one->toString())) {
|
if ($this->compare($limit) == -((int) $one->toString())) {
|
||||||
$oneint = (int) $one->toString();
|
$oneint = (int) $one->toString();
|
||||||
$thisint = (int) $this->toString();
|
$thisint = (int) $this->toString();
|
||||||
|
@ -405,16 +405,16 @@ abstract class Unit_Math_BigInteger_TestCase extends PhpseclibTestCase
|
|||||||
{
|
{
|
||||||
$min = new \phpseclib\Math\BigInteger('20');
|
$min = new \phpseclib\Math\BigInteger('20');
|
||||||
$max = new \phpseclib\Math\BigInteger('20000');
|
$max = new \phpseclib\Math\BigInteger('20000');
|
||||||
$this->assertSame((string) $max, (string) $min->max($max));
|
$this->assertSame((string) $max, (string) \phpseclib\Math\BigInteger::max($min, $max));
|
||||||
$this->assertSame((string) $max, (string) $max->max($min));
|
$this->assertSame((string) $max, (string) \phpseclib\Math\BigInteger::max($max, $min));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMin()
|
public function testMin()
|
||||||
{
|
{
|
||||||
$min = new \phpseclib\Math\BigInteger('20');
|
$min = new \phpseclib\Math\BigInteger('20');
|
||||||
$max = new \phpseclib\Math\BigInteger('20000');
|
$max = new \phpseclib\Math\BigInteger('20000');
|
||||||
$this->assertSame((string) $min, (string) $min->min($max));
|
$this->assertSame((string) $min, (string) \phpseclib\Math\BigInteger::min($min, $max));
|
||||||
$this->assertSame((string) $min, (string) $max->min($min));
|
$this->assertSame((string) $min, (string) \phpseclib\Math\BigInteger::min($max, $min));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testLoopForeach()
|
public function testLoopForeach()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user