public static function round($number, $precision = 0, $mode = PHP_ROUND_HALF_UP)
    {
        self::assertNumberFormat($number);
        if (!is_numeric($precision) || $precision < 0) {
            throw new \InvalidArgumentException('The provided precision should be a positive number');
        }

        // Round the number in both directions (up/down) before choosing one.
        $rounding_increment = bcdiv('1', pow(10, $precision), $precision);
        if (self::compare($number, '0') == 1) {
            $rounded_up = bcadd($number, $rounding_increment, $precision);
        } else {
            $rounded_up = bcsub($number, $rounding_increment, $precision);
        }
        $rounded_down = bcsub($number, 0, $precision);
        // The rounding direction is based on the first decimal after $precision.
        $number_parts = explode('.', $number);
        $decimals = !empty($number_parts[1]) ? $number_parts[1] : '0';
        $relevant_decimal = isset($decimals[$precision]) ? $decimals[$precision] : 0;
        if ($relevant_decimal < 5) {
            $number = $rounded_down;
        } elseif ($relevant_decimal == 5) {
            if ($mode == PHP_ROUND_HALF_UP) {
                $number = $rounded_up;
            } elseif ($mode == PHP_ROUND_HALF_DOWN) {
                $number = $rounded_down;
            } elseif ($mode == PHP_ROUND_HALF_EVEN) {
                $integer = bcmul($rounded_up, pow(10, $precision), 0);
                $number = bcmod($integer, '2') == 0 ? $rounded_up : $rounded_down;
            } elseif ($mode == PHP_ROUND_HALF_ODD) {
                $integer = bcmul($rounded_up, pow(10, $precision), 0);
                $number = bcmod($integer, '2') != 0 ? $rounded_up : $rounded_down;
            }
        } elseif ($relevant_decimal > 5) {
            $number = $rounded_up;
        }

        return $number;
    }