e = 2.718281828459045
pi = 3.141592653589793
tau = 6.283185307179586

inf = 1.0 / 0.0
nan = 0.0 / 0.0

def factorial(x: int) -> int:
    _F = (1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880,  3628800,  39916800,  479001600,  6227020800,  87178291200,  1307674368000,  20922789888000,  355687428096000,  6402373705728000,  121645100408832000,  2432902008176640000)
    if not (0 <= x <= 20):
        raise ValueError("factorial is only supported for 0 <= x <= 20")
    return _F[x]

def isnan(x: float) -> bool:
    """
    isnan(float) -> bool

    Return True if float arg is a NaN, else False.
    """
    test = x == x
    # if it is true then it is a number
    if test:
        return False
    return True

def isinf(x: float) -> bool:
    """
    isinf(float) -> bool:

    Return True if float arg is an INF, else False.
    """
    return x == inf or x == -inf

def isfinite(x: float) -> bool:
    """
    isfinite(float) -> bool

    Return True if x is neither an infinity nor a NaN,
    and False otherwise.
    """
    if isnan(x) or isinf(x):
        return False
    return True

def ceil(x: float) -> float:
    """
    ceil(float) -> float

    Return the ceiling of x as an Integral.
    This is the smallest integer >= x.
    """
    @pure
    @llvm
    def f(x: float) -> float:
        declare double @llvm.ceil.f64(double)
        %y = call double @llvm.ceil.f64(double %x)
        ret double %y

    return f(x)

def floor(x: float) -> float:
    """
    floor(float) -> float

    Return the floor of x as an Integral.
    This is the largest integer <= x.
    """
    @pure
    @llvm
    def f(x: float) -> float:
        declare double @llvm.floor.f64(double)
        %y = call double @llvm.floor.f64(double %x)
        ret double %y

    return f(x)

def fabs(x: float) -> float:
    """
    fabs(float) -> float

    Returns the absolute value of a floating point number.
    """
    @pure
    @llvm
    def f(x: float) -> float:
        declare double @llvm.fabs.f64(double)
        %y = call double @llvm.fabs.f64(double %x)
        ret double %y

    return f(x)

def fmod(x: float, y: float) -> float:
    """
    fmod(float, float) -> float

    Returns the remainder of x divided by y.
    """
    @pure
    @llvm
    def f(x: float, y: float) -> float:
        %z = frem double %x, %y
        ret double %z

    return f(x, y)

def exp(x: float) -> float:
    """
    exp(float) -> float

    Returns the value of e raised to the xth power.
    """
    @pure
    @llvm
    def f(x: float) -> float:
        declare double @llvm.exp.f64(double)
        %y = call double @llvm.exp.f64(double %x)
        ret double %y

    return f(x)

def expm1(x: float) -> float:
    """
    expm1(float) -> float

    Return e raised to the power x, minus 1. expm1 provides
    a way to compute this quantity to full precision.
    """
    return _C.expm1(x)

def ldexp(x: float, i: int) -> float:
    """
    ldexp(float, int) -> float

    Returns x multiplied by 2 raised to the power of exponent.
    """
    return _C.ldexp(x, i)

def log(x: float, base: float = e) -> float:
    """
    log(float) -> float

    Returns the natural logarithm (base-e logarithm) of x.
    """
    @pure
    @llvm
    def f(x: float) -> float:
        declare double @llvm.log.f64(double)
        %y = call double @llvm.log.f64(double %x)
        ret double %y

    if base == e:
        return f(x)
    else:
        return f(x)/f(base)

def log2(x: float) -> float:
    """
    log2(float) -> float

    Return the base-2 logarithm of x.
    """
    @pure
    @llvm
    def f(x: float) -> float:
        declare double @llvm.log2.f64(double)
        %y = call double @llvm.log2.f64(double %x)
        ret double %y

    return f(x)

def log10(x: float) -> float:
    """
    log10(float) -> float

    Returns the common logarithm (base-10 logarithm) of x.
    """
    @pure
    @llvm
    def f(x: float) -> float:
        declare double @llvm.log10.f64(double)
        %y = call double @llvm.log10.f64(double %x)
        ret double %y

    return f(x)

def degrees(x: float) -> float:
    """
    degrees(float) -> float

    Convert angle x from radians to degrees.
    """
    radToDeg = 180.0/pi
    return x * radToDeg

def radians(x: float) -> float:
    """
    radians(float) -> float

    Convert angle x from degrees to radians.
    """
    degToRad = pi/180.0
    return x * degToRad

def sqrt(x: float) -> float:
    """
    sqrt(float) -> float

    Returns the square root of x.
    """
    @pure
    @llvm
    def f(x: float) -> float:
        declare double @llvm.sqrt.f64(double)
        %y = call double @llvm.sqrt.f64(double %x)
        ret double %y

    return f(x)

def pow(x: float, y: float) -> float:
    """
    pow(float, float) -> float

    Returns x raised to the power of y.
    """
    @pure
    @llvm
    def f(x: float, y: float) -> float:
        declare double @llvm.pow.f64(double, double)
        %z = call double @llvm.pow.f64(double %x, double %y)
        ret double %z

    return f(x, y)

def acos(x: float) -> float:
    """
    acos(float) -> float

    Returns the arc cosine of x in radians.
    """
    return _C.acos(x)

def asin(x: float) -> float:
    """
    asin(float) -> float

    Returns the arc sine of x in radians.
    """
    return _C.asin(x)

def atan(x: float) -> float:
    """
    atan(float) -> float

    Returns the arc tangent of x in radians.
    """
    return _C.atan(x)

def atan2(y: float, x: float) -> float:
    """
    atan2(float, float) -> float

    Returns the arc tangent in radians of y/x based
    on the signs of both values to determine the
    correct quadrant.
    """
    return _C.atan2(y, x)

def cos(x: float) -> float:
    """
    cos(float) -> float

    Returns the cosine of a radian angle x.
    """
    @pure
    @llvm
    def f(x: float) -> float:
        declare double @llvm.cos.f64(double)
        %y = call double @llvm.cos.f64(double %x)
        ret double %y

    return f(x)

def sin(x: float) -> float:
    """
    sin(float) -> float

    Returns the sine of a radian angle x.
    """
    @pure
    @llvm
    def f(x: float) -> float:
        declare double @llvm.sin.f64(double)
        %y = call double @llvm.sin.f64(double %x)
        ret double %y

    return f(x)

def hypot(x: float, y: float) -> float:
    """
    hypot(float, float) -> float

    Return the Euclidean norm.
    This is the length of the vector from the
    origin to point (x, y).
    """
    return _C.hypot(x, y)

def tan(x: float) -> float:
    """
    tan(float) -> float

    Return the tangent of a radian angle x.
    """
    return _C.tan(x)

def cosh(x: float) -> float:
    """
    cosh(float) -> float

    Returns the hyperbolic cosine of x.
    """
    return _C.cosh(x)

def sinh(x: float) -> float:
    """
    sinh(float) -> float

    Returns the hyperbolic sine of x.
    """
    return _C.sinh(x)

def tanh(x: float) -> float:
    """
    tanh(float) -> float

    Returns the hyperbolic tangent of x.
    """
    return _C.tanh(x)

def acosh(x: float) -> float:
    """
    acosh(float) -> float

    Return the inverse hyperbolic cosine of x.
    """
    return _C.acosh(x)

def asinh(x: float) -> float:
    """
    asinh(float) -> float

    Return the inverse hyperbolic sine of x.
    """
    return _C.asinh(x)

def atanh(x: float) -> float:
    """
    atanh(float) -> float

    Return the inverse hyperbolic tangent of x.
    """
    return _C.atanh(x)

def copysign(x: float, y: float) -> float:
    """
    copysign(float, float) -> float

    Return a float with the magnitude (absolute value) of
    x but the sign of y.
    """
    @pure
    @llvm
    def f(x: float, y: float) -> float:
        declare double @llvm.copysign.f64(double, double)
        %z = call double @llvm.copysign.f64(double %x, double %y)
        ret double %z

    return f(x, y)

def log1p(x: float) -> float:
    """
    log1p(float) -> float

    Return the natural logarithm of 1+x (base e).
    """
    return _C.log1p(x)

def trunc(x: float) -> float:
    """
    trunc(float) -> float

    Return the Real value x truncated to an Integral
    (usually an integer).
    """
    @pure
    @llvm
    def f(x: float) -> float:
        declare double @llvm.trunc.f64(double)
        %y = call double @llvm.trunc.f64(double %x)
        ret double %y

    return f(x)

def erf(x: float) -> float:
    """
    erf(float) -> float

    Return the error function at x.
    """
    return _C.erf(x)

def erfc(x: float) -> float:
    """
    erfc(float) -> float

    Return the complementary error function at x.
    """
    return _C.erfc(x)

def gamma(x: float) -> float:
    """
    gamma(float) -> float

    Return the Gamma function at x.
    """
    return _C.tgamma(x)

def lgamma(x: float) -> float:
    """
    lgamma(float) -> float

    Return the natural logarithm of
    the absolute value of the Gamma function at x.
    """
    return _C.lgamma(x)

def remainder(x: float, y: float) -> float:
    """
    remainder(float, float) -> float

    Return the IEEE 754-style remainder of x with respect to y.
    For finite x and finite nonzero y, this is the difference
    x - n*y, where n is the closest integer to the exact value
    of the quotient x / y. If x / y is exactly halfway between
    two consecutive integers, the nearest even integer is used
    for n.
    """
    return _C.remainder(x, y)

def gcd(a: float, b: float) -> float:
    """
    gcd(float, float) -> float

    returns greatest common divisor of x and y.
    """
    a = abs(a)
    b = abs(b)
    while a:
        a, b = b%a, a
    return b

@pure
def frexp(x: float) -> Tuple[float, int]:
    """
    frexp(float) -> Tuple[float, int]

    The returned value is the mantissa and the integer pointed
    to by exponent is the exponent. The resultant value is
    x = mantissa * 2 ^ exponent.
    """
    tmp = i32(0)
    res = _C.frexp(float(x), __ptr__(tmp))
    return (res, int(tmp))

@pure
def modf(x: float) -> Tuple[float, float]:
    """
    modf(float) -> Tuple[float, float]

    The returned value is the fraction component (part after
    the decimal), and sets integer to the integer component.
    """
    tmp = 0.0
    res = _C.modf(float(x), __ptr__(tmp))
    return (res, tmp)

def isclose(a: float, b: float, rel_tol: float = 1e-09, abs_tol: float = 0.0) -> bool:
    """
    isclose(float, float) -> bool

    Return True if a is close in value to b, and False otherwise.
    For the values to be considered close, the difference between them
    must be smaller than at least one of the tolerances.
    """

    # short circuit exact equality -- needed to catch two
    # infinities of the same sign. And perhaps speeds things
    # up a bit sometimes.
    if a == b:
        return True

    # This catches the case of two infinities of opposite sign, or
    # one infinity and one finite number. Two infinities of opposite
    # sign would otherwise have an infinite relative tolerance.
    # Two infinities of the same sign are caught by the equality check
    # above.
    if a == inf or b == inf:
        return False

    # NAN is not close to anything, not even itself
    if a == nan or b == nan:
        return False

    # regular computation
    diff = fabs(b - a)

    return (((diff <= fabs(rel_tol * b)) or
            (diff <= fabs(rel_tol * a))) or
            (diff <= abs_tol))