/** * Calculates the greatest common divisor and Bezout's identity. * * Say you have 693 and 609. The GCD is 21. Bezout's identity states that there exist integers x and y such that * 693*x + 609*y == 21. In point of fact, there are actually an infinite number of x and y combinations and which * combination is returned is dependant upon which mode is in use. See * {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity Bezout's identity - Wikipedia} for more information. * * Here's an example: * <code> * <?php * include 'Math/BigInteger.php'; * * $a = new Math_BigInteger(693); * $b = new Math_BigInteger(609); * * extract($a->extendedGCD($b)); * * echo $gcd->toString() . "\r\n"; // outputs 21 * echo $a->toString() * $x->toString() + $b->toString() * $y->toString(); // outputs 21 * ?> * </code> * * @param Math_BigInteger $n * @return Math_BigInteger * @access public * @internal Calculates the GCD using the binary xGCD algorithim described in * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=19 HAC 14.61}. As the text above 14.61 notes, * the more traditional algorithim requires "relatively costly multiple-precision divisions". */ function extendedGCD($n) { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: extract(gmp_gcdext($this->value, $n->value)); return array('gcd' => $this->_normalize(new Math_BigInteger($g)), 'x' => $this->_normalize(new Math_BigInteger($s)), 'y' => $this->_normalize(new Math_BigInteger($t))); case MATH_BIGINTEGER_MODE_BCMATH: // it might be faster to use the binary xGCD algorithim here, as well, but (1) that algorithim works // best when the base is a power of 2 and (2) i don't think it'd make much difference, anyway. as is, // the basic extended euclidean algorithim is what we're using. $u = $this->value; $v = $n->value; $a = '1'; $b = '0'; $c = '0'; $d = '1'; while (bccomp($v, '0', 0) != 0) { $q = bcdiv($u, $v, 0); $temp = $u; $u = $v; $v = bcsub($temp, bcmul($v, $q, 0), 0); $temp = $a; $a = $c; $c = bcsub($temp, bcmul($a, $q, 0), 0); $temp = $b; $b = $d; $d = bcsub($temp, bcmul($b, $q, 0), 0); } return array('gcd' => $this->_normalize(new Math_BigInteger($u)), 'x' => $this->_normalize(new Math_BigInteger($a)), 'y' => $this->_normalize(new Math_BigInteger($b))); } $y = $n->copy(); $x = $this->copy(); $g = new Math_BigInteger(); $g->value = array(1); while (!($x->value[0] & 1 || $y->value[0] & 1)) { $x->_rshift(1); $y->_rshift(1); $g->_lshift(1); } $u = $x->copy(); $v = $y->copy(); $a = new Math_BigInteger(); $b = new Math_BigInteger(); $c = new Math_BigInteger(); $d = new Math_BigInteger(); $a->value = $d->value = $g->value = array(1); $b->value = $c->value = array(); while (!empty($u->value)) { while (!($u->value[0] & 1)) { $u->_rshift(1); if (!empty($a->value) && $a->value[0] & 1 || !empty($b->value) && $b->value[0] & 1) { $a = $a->add($y); $b = $b->subtract($x); } $a->_rshift(1); $b->_rshift(1); } while (!($v->value[0] & 1)) { $v->_rshift(1); if (!empty($d->value) && $d->value[0] & 1 || !empty($c->value) && $c->value[0] & 1) { $c = $c->add($y); $d = $d->subtract($x); } $c->_rshift(1); $d->_rshift(1); } if ($u->compare($v) >= 0) { $u = $u->subtract($v); $a = $a->subtract($c); $b = $b->subtract($d); } else { $v = $v->subtract($u); $c = $c->subtract($a); $d = $d->subtract($b); } } return array('gcd' => $this->_normalize($g->multiply($v)), 'x' => $this->_normalize($c), 'y' => $this->_normalize($d)); }
echo gmp_strval($div1) . "\n"; // gmp_fact $fact1 = gmp_fact(5); // 5 * 4 * 3 * 2 * 1 echo gmp_strval($fact1) . "\n"; $fact2 = gmp_fact(50); // 50 * 49 * 48, ... etc echo gmp_strval($fact2) . "\n"; // gmp_gcd $gcd = gmp_gcd("12", "21"); echo gmp_strval($gcd) . "\n"; // gmp_gcdext $a = gmp_init(12); $b = gmp_init(21); $g = gmp_gcd($a, $b); $r = gmp_gcdext($a, $b); $check_gcd = gmp_strval($g) == gmp_strval($r['g']); $eq_res = gmp_add(gmp_mul($a, $r['s']), gmp_mul($b, $r['t'])); $check_res = gmp_strval($g) == gmp_strval($eq_res); if ($check_gcd && $check_res) { $fmt = "Solution: %d*%d + %d*%d = %d\n"; printf($fmt, gmp_strval($a), gmp_strval($r['s']), gmp_strval($b), gmp_strval($r['t']), gmp_strval($r['g'])); } else { echo "Error while solving the equation\n"; } // gmp_hamdist $ham1 = gmp_init("1001010011", 2); $ham2 = gmp_init("1011111100", 2); echo gmp_hamdist($ham1, $ham2) . "\n"; echo gmp_popcount(gmp_xor($ham1, $ham2)) . "\n"; // gmp_init (although that's probably tested well by now)
/** * Finds the greatest common denominator of two numbers using the extended * Euclidean algorithm. * * The returned array is ( a0, b0, gcd( a, b ) ), where * a0 * a + b0 * b = gcd( a, b ) * * @param resource $a The first number * @param resource $b The second number * @return array(resource) */ public function gcd($a, $b) { $result = gmp_gcdext($a, $b); return array($result['s'], $result['t'], $result['g']); }
<?php $n = gmp_init("34293864345"); $n1 = gmp_init("23434293864345"); $a = array(array(123, 45), array(4341, 9734), array(23487, 333), array(-234234, -123123), array(-100, -2234), array(345, "34587345"), array(345, "0"), array("345556456", 345873), array("34545345556456", "323432445873"), array($n, $n1)); foreach ($a as $val) { $r = gmp_gcdext($val[0], $val[1]); var_dump(gmp_strval($r['g'])); var_dump(gmp_strval($r['s'])); var_dump(gmp_strval($r['t'])); } var_dump(gmp_gcdext($val[0], array())); var_dump(gmp_gcdext(array(), array())); var_dump(gmp_gcdext(array(), array(), 1)); var_dump(gmp_gcdext(array())); var_dump(gmp_gcdext()); echo "Done\n";
public function extendedGCD($n) { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $_gmp_gcdext = gmp_gcdext($this->value, $n->value); $g = $_gmp_gcdext['g']; $s = $_gmp_gcdext['s']; $t = $_gmp_gcdext['t']; return array('gcd' => $this->_normalize(new Math_BigInteger($g)), 'x' => $this->_normalize(new Math_BigInteger($s)), 'y' => $this->_normalize(new Math_BigInteger($t))); case MATH_BIGINTEGER_MODE_BCMATH: $u = $this->value; $v = $n->value; $a = '1'; $b = '0'; $c = '0'; $d = '1'; while (bccomp($v, '0', 0) != 0) { $q = bcdiv($u, $v, 0); $temp = $u; $u = $v; $v = bcsub($temp, bcmul($v, $q, 0), 0); $temp = $a; $a = $c; $c = bcsub($temp, bcmul($a, $q, 0), 0); $temp = $b; $b = $d; $d = bcsub($temp, bcmul($b, $q, 0), 0); } return array('gcd' => $this->_normalize(new Math_BigInteger($u)), 'x' => $this->_normalize(new Math_BigInteger($a)), 'y' => $this->_normalize(new Math_BigInteger($b))); } $y = $n->copy(); $x = $this->copy(); $g = new Math_BigInteger(); $g->value = array(1); while (!($x->value[0] & 1 || $y->value[0] & 1)) { $x->_rshift(1); $y->_rshift(1); $g->_lshift(1); } $u = $x->copy(); $v = $y->copy(); $a = new Math_BigInteger(); $b = new Math_BigInteger(); $c = new Math_BigInteger(); $d = new Math_BigInteger(); $a->value = $d->value = $g->value = array(1); $b->value = $c->value = array(); while (!empty($u->value)) { while (!($u->value[0] & 1)) { $u->_rshift(1); if (!empty($a->value) && $a->value[0] & 1 || !empty($b->value) && $b->value[0] & 1) { $a = $a->add($y); $b = $b->subtract($x); } $a->_rshift(1); $b->_rshift(1); } while (!($v->value[0] & 1)) { $v->_rshift(1); if (!empty($d->value) && $d->value[0] & 1 || !empty($c->value) && $c->value[0] & 1) { $c = $c->add($y); $d = $d->subtract($x); } $c->_rshift(1); $d->_rshift(1); } if (0 <= $u->compare($v)) { $u = $u->subtract($v); $a = $a->subtract($c); $b = $b->subtract($d); } else { $v = $v->subtract($u); $c = $c->subtract($a); $d = $d->subtract($b); } } return array('gcd' => $this->_normalize($g->multiply($v)), 'x' => $this->_normalize($c), 'y' => $this->_normalize($d)); }
public static function add(\fpoirotte\Pssht\ECC\Curve $curve, \fpoirotte\Pssht\ECC\Point $P, \fpoirotte\Pssht\ECC\Point $Q) { $mod = $curve->getModulus(); $xP = $P->coordinates['x']; $yP = $P->coordinates['y']; $xQ = $Q->coordinates['x']; $yQ = $Q->coordinates['y']; if (!gmp_cmp($xP, $xQ) && !gmp_cmp($yP, $yQ)) { $alphanum = gmp_add(gmp_mul('3', gmp_pow($xP, '2')), $curve->getA()); $alphaden = gmp_mul('2', $yP); } else { $alphanum = gmp_sub($yQ, $yP); $alphaden = gmp_sub($xQ, $xP); } $bezout = gmp_gcdext($alphaden, $mod); $alpha = gmp_mod(gmp_mul($alphanum, $bezout['s']), $mod); $xR = gmp_sub(gmp_sub(gmp_pow($alpha, '2'), $xP), $xQ); $yR = gmp_sub(gmp_mul($alpha, gmp_sub($xP, $xR)), $yP); return new static(gmp_mod(gmp_add($xR, $mod), $mod), gmp_mod(gmp_add($yR, $mod), $mod)); }