A universal function to compute the modulus of this vector and
another tensor element-wise.

@param mixed $b
@throws \InvalidArgumentException
@return mixed
334840
public function mod($b)
    {
        switch (true) {
            case $b instanceof Vector:
                $c = $this->modVector($b);
                break;

            case $b instanceof Matrix:
                $c = $this->modMatrix($b);
                break;

            case is_int($b) or is_float($b):
                $c = $this->modScalar($b);
                break;

            default:
                throw new InvalidArgumentException('Cannot mod vector'
                    . ' with a ' . gettype($b) . '.');
        }

        return $c;
    }
679998
public function subtract($b)
    {
        switch (true) {
            case $b instanceof Matrix:
                $c = $this->subtractMatrix($b);
                break;

            case $b instanceof ColumnVector:
                $c = $this->subtractColumnVector($b);
                break;
                
            case $b instanceof Vector:
                $c = $this->subtractVector($b);
                break;

            case is_int($b) or is_float($b):
                $c = $this->subtractScalar($b);
                break;

            default:
                throw new InvalidArgumentException('Cannot subtract a '
                    . gettype($b) . ' from a matrix.');
        }

        return $c;
    }
38794
public function convolve(Vector $b, int $stride = 1) : self
    {
        if ($b->size() > $this->n) {
            throw new InvalidArgumentException('Vector B cannot be'
                . ' longer than Vector A.');
        }

        if ($stride < 1) {
            throw new InvalidArgumentException('Stride cannot be'
                . " less than 1, $stride given.");
        }

        $c = [];

        for ($i = 0; $i < $this->n; $i += $stride) {
            $sigma = 0;

            foreach ($b as $j => $valueB) {
                $sigma += ($this->a[$i - (int) $j] ?? 0) * $valueB;
            }

            $c[] = $sigma;
        }

        return static::quick($c);
    }
707496
public function modulus()
    {
        if ($this->isReal()) {
            //sqrt(r^2 + 0^2) = sqrt(r^2) = abs(r)
            /** @noinspection PhpUndefinedMethodInspection */
            return $this->value['real']->abs();
        }
        //get r^2 and i^2
        $sqrR = array(
            'n' => gmp_pow($this->value['real']->numerator()->gmp(), 2),
            'd' => gmp_pow($this->value['real']->denominator()->gmp(), 2)
        );
        $sqrI = array(
            'n' => gmp_pow($this->value['imaginary']->numerator()->gmp(), 2),
            'd' => gmp_pow($this->value['imaginary']->denominator()->gmp(), 2)
        );
        //r^2 + i^2
        $den = $this->lcm($sqrR['d'], $sqrI['d']);
        $numRaw = gmp_strval(
            gmp_add(
                gmp_div_q(gmp_mul($sqrR['n'], $den), $sqrR['d']),
                gmp_div_q(gmp_mul($sqrI['n'], $den), $sqrI['d'])
            )
        );
        $num = TypeFactory::createInt($numRaw);

        //sqrt(num/den) = sqrt(num)/sqrt(den)
        //now this a fudge - we ought to be able to get a proper square root using
        //factors etc but what we do instead is to do an approximation by converting
        //to intermediate rationals using as much precision as we can i.e.
        // rNum = GMPRationaType(sqrt(num))
        // rDen = GMPRationalType(sqrt(den))
        // mod = rN/1 * 1/rD
        $rNum = RationalTypeFactory::fromFloat(sqrt($num()));
        $rDen = RationalTypeFactory::fromFloat(sqrt(gmp_strval($den)));
        $modN = gmp_mul($rNum->numerator()->gmp(), $rDen->denominator()->gmp());
        $modD = gmp_mul($rNum->denominator()->gmp(), $rDen->numerator()->gmp());

        return RationalTypeFactory::create(
            (int) gmp_strval($modN),
            (int) gmp_strval($modD)
        );
    }
250043
public function distance(array $a, array $b): float
    {
        if (count($a) !== count($b)) {
            throw InvalidArgumentException::arraySizeNotMatch();
        }

        $differences = [];
        $count = count($a);

        for ($i = 0; $i < $count; ++$i) {
            $differences[] = abs($a[$i] - $b[$i]);
        }

        return max($differences);
    }
388727
private function lcm($a, $b)
    {
        return \abs(($a * $b) / $this->gcd($a, $b));
    }
566118
protected function gcd($a, $b)
    {
        while ($b != 0) {
            $remainder = $a % $b;
            $a = $b;
            $b = $remainder;
        }
        return abs($a);
    }
100162
public function project(Vector $b) : self
    {
        $bHat = $this->dot($b) / ($b->l2Norm() ** 2);

        return $b->multiply($bHat);
    }
720957
public function toBase($base)
    {
        if ($this->normalize()->hasDecimals()) {
            throw new \InvalidArgumentException('Argument number is not an integer');
        }

        // do not mutate, only support positive integers
        $number = ltrim((string) $this, '-');
        if (static::$gmpSupport && $base <= 62) {
            return static::baseConvert($number, 10, $base);
        }

        $result   = '';
        $baseChar = static::getBaseChar($base);
        while (bccomp($number, 0) != 0) { // still data to process
            $rem    = bcmod($number, $base); // calc the remainder
            $number = bcdiv(bcsub($number, $rem), $base);
            $result = $baseChar[$rem] . $result;
        }

        $result = $result ? $result : $baseChar[0];

        return (string) $result;
    }
55080
public function add($b)
    {
        switch (true) {
            case $b instanceof Matrix:
                $c = $this->addMatrix($b);
                break;

            case $b instanceof ColumnVector:
                $c = $this->addColumnVector($b);
                break;
            
            case $b instanceof Vector:
                $c = $this->addVector($b);
                break;

            case is_int($b) or is_float($b):
                $c = $this->addScalar($b);
                break;

            default:
                throw new InvalidArgumentException('Cannot add matrix'
                    . ' to a ' . gettype($b) . '.');
        }

        return $c;
    }
82868
public function sub($a, $b)
    {
        $a = $this->convert($a);
        $b = $this->convert($b);
        switch ($this->arbitrate($a, $b)) {
            case 'int':
                return $this->calcEngine->intSub($a, $b);
            case 'float':
                return $this->calcEngine->floatSub($a, $b);
            case 'whole':
                return $this->calcEngine->wholeSub($a, $b);
            case 'natural':
                return $this->calcEngine->naturalSub($a, $b);
            case 'rational':
                return $this->calcEngine->rationalSub($a, $b);
            case 'complex':
                return $this->calcEngine->complexSub($a, $b);
            case 'complex:numeric':
                return $this->calcEngine->complexSub($a, $b->asComplex());
            case 'numeric:complex':
                return $this->calcEngine->complexSub($a->asComplex(), $b);
        }
    }
716013
public static function mul($int1, $int2)
    {
        if (!static::is($int1) || !static::is($int2)) {
            throw new \InvalidArgumentException(
                "The \$int1 and \$int2 parameters must be of type int (or string representing a big int)."
            );
        }

        if (is_int($int1) && is_int($int2)) {
            return ($int1 * $int2);
        } elseif (function_exists('bcmul')) {
            return bcmul($int1, $int2);
        }

        throw new \RuntimeException("The BCMath library is not available."); // @codeCoverageIgnore
    }
242890
public function div($a, $b)
    {
        $a = $this->convert($a);
        $b = $this->convert($b);
        switch ($this->arbitrate($a, $b)) {
            case 'int':
            case 'whole':
            case 'natural':
                return $this->calcEngine->intDiv($a, $b);
            case 'rational':
                return $this->calcEngine->rationalDiv($a, $b);
            case 'complex':
                return $this->calcEngine->complexDiv($a, $b);
            case 'complex:numeric':
                return $this->calcEngine->complexDiv($a, $b->asComplex());
            case 'numeric:complex':
                return $this->calcEngine->complexDiv($a->asComplex(), $b);
            default:
                return $this->calcEngine->floatDiv($a, $b);
        }
    }
242819
public function bitwiseXOr($x)
    {
        switch (MATH_BIGINTEGER_MODE) {
            case MATH_BIGINTEGER_MODE_GMP:
                $temp = new BigInteger();
                $temp->value = gmp_xor($this->value, $x->value);
                return $this->protectedNormalize($temp);
            case MATH_BIGINTEGER_MODE_BCMATH:
                $left = $this->toBytes();
                $right = $x->toBytes();
                $length = max(strlen($left), strlen($right));
                $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
                $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
                return $this->protectedNormalize(new BigInteger($left ^ $right, 256));
        }
        $length = max(count($this->value), count($x->value));
        $result = $this->copy();
        $result->value = array_pad($result->value, $length, 0);
        $x->value = array_pad($x->value, $length, 0);
        for ($i = 0; $i < $length; ++ $i) {
            $result->value[$i] ^= $x->value[$i];
        }
        return $this->protectedNormalize($result);
    }
1328798
public static function mul($float1, $float2)
    {
        if (!static::is($float1) || !static::is($float2)) {
            throw new \InvalidArgumentException("The \$float1 and \$float2 parameters must be of type float.");
        }

        return ($float1 * $float2);
    }
78486
public function power($a, $b)
    {
        return bcpow($this->bcNormalize($a), $this->bcNormalize($b));
    }
717276
public function computeWithoutBcMath(DecimalNumber $a, DecimalNumber $b)
    {
        if ($a->isNegative()) {
            if ($b->isNegative()) {
                // if both numbers are negative,
                // we can just add them as positive numbers and then invert the sign
                // f(x, y) = -(|x| + |y|)
                // eg. f(-1, -2) = -(|-1| + |-2|) = -3
                // eg. f(-2, -1) = -(|-2| + |-1|) = -3
                return $this
                    ->computeWithoutBcMath($a->toPositive(), $b->toPositive())
                    ->invert();
            }
            // if the number is negative and the addend positive,
            // perform an inverse subtraction by inverting the terms
            // f(x, y) = y - |x|
            // eg. f(-2, 1) = 1 - |-2| = -1
            // eg. f(-1, 2) = 2 - |-1| = 1
            // eg. f(-1, 1) = 1 - |-1| = 0
            return $b->minus(
                $a->toPositive()
            );
        }

        if ($b->isNegative()) {
            // if the number is positive and the addend is negative
            // perform subtraction instead: 2 - 1
            // f(x, y) = x - |y|
            // f(2, -1) = 2 - |-1| = 1
            // f(1, -2) = 1 - |-2| = -1
            // f(1, -1) = 1 - |-1| = 0
            return $a->minus(
                $b->toPositive()
            );
        }

        // optimization: 0 + x = x
        if ('0' === (string) $a) {
            return $b;
        }

        // optimization: x + 0 = x
        if ('0' === (string) $b) {
            return $a;
        }

        // pad coefficients with leading/trailing zeroes
        list($coeff1, $coeff2) = $this->normalizeCoefficients($a, $b);

        // compute the coefficient sum
        $sum = $this->addStrings($coeff1, $coeff2);

        // both signs are equal, so we can use either
        $sign = $a->getSign();

        // keep the bigger exponent
        $exponent = max($a->getExponent(), $b->getExponent());

        return new DecimalNumber($sign . $sum, $exponent);
    }