content: #
  # Copyright 2023 EA Authors.
  #
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  #
  #    https://www.apache.org/licenses/LICENSE-2.0
  #
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  #
  
  @pure
  @llvm
  def _inf() -> float:
      ret double 0x7FF0000000000000
  
  @pure
  @llvm
  def _nan() -> float:
      ret double 0x7FF8000000000000
  
  e = 2.7182818284590452354
  pi = 3.14159265358979323846
  tau = 6.28318530717958647693
  inf = _inf()
  nan = _nan()
  
  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.
      """
      @pure
      @llvm
      def f(x: float) -> bool:
          %y = fcmp uno double %x, 0.000000e+00
          %z = zext i1 %y to i8
          ret i8 %z
  
      return f(x)
  
  def isinf(x: float) -> bool:
      """
      isinf(float) -> bool:
  
      Return True if float arg is an INF, else False.
      """
      @pure
      @llvm
      def f(x: float) -> bool:
          declare double @llvm.fabs.f64(double)
          %a = call double @llvm.fabs.f64(double %x)
          %b = fcmp oeq double %a, 0x7FF0000000000000
          %c = zext i1 %b to i8
          ret i8 %c
  
      return f(x)
  
  def isfinite(x: float) -> bool:
      """
      isfinite(float) -> bool
  
      Return True if x is neither an infinity nor a NaN,
      and False otherwise.
      """
      return not (isnan(x) or isinf(x))
  
  def _check1(arg: float, r: float, can_overflow: bool = False):
      if __py_numerics__:
          if isnan(r) and not isnan(arg):
              raise ValueError("math domain error")
  
          if isinf(r) and isfinite(arg):
              if can_overflow:
                  raise OverflowError("math range error")
              else:
                  raise ValueError("math domain error")
  
      return r
  
  def _check2(x: float, y: float, r: float, can_overflow: bool = False):
      if __py_numerics__:
          if isnan(r) and not isnan(x) and not isnan(y):
              raise ValueError("math domain error")
  
          if isinf(r) and isfinite(x) and isfinite(y):
              if can_overflow:
                  raise OverflowError("math range error")
              else:
                  raise ValueError("math domain error")
  
      return r
  
  def ceil(x: float) -> int:
      """
      ceil(float) -> int
  
      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 int(f(x))
  
  def floor(x: float) -> int:
      """
      floor(float) -> int
  
      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 int(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 _check1(x, f(x), True)
  
  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 _check1(x, _C.expm1(x), True)
  
  def ldexp(x: float, i: int) -> float:
      """
      ldexp(float, int) -> float
  
      Returns x multiplied by 2 raised to the power of exponent.
      """
      return _check1(x, _C.ldexp(x, i32(i)), True)
  
  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 _check1(x, f(x))
      else:
          return _check1(x, f(x)) / _check1(base, 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 _check1(x, 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 _check1(x, 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 _check1(x, 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 _check2(x, y, f(x, y), True)
  
  def acos(x: float) -> float:
      """
      acos(float) -> float
  
      Returns the arc cosine of x in radians.
      """
      return _check1(x, _C.acos(x))
  
  def asin(x: float) -> float:
      """
      asin(float) -> float
  
      Returns the arc sine of x in radians.
      """
      return _check1(x, _C.asin(x))
  
  def atan(x: float) -> float:
      """
      atan(float) -> float
  
      Returns the arc tangent of x in radians.
      """
      return _check1(x, _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 _check2(x, y, _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 _check1(x, 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 _check1(x, 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 _check2(x, y, _C.hypot(x, y), True)
  
  def tan(x: float) -> float:
      """
      tan(float) -> float
  
      Return the tangent of a radian angle x.
      """
      return _check1(x, _C.tan(x))
  
  def cosh(x: float) -> float:
      """
      cosh(float) -> float
  
      Returns the hyperbolic cosine of x.
      """
      return _check1(x, _C.cosh(x), True)
  
  def sinh(x: float) -> float:
      """
      sinh(float) -> float
  
      Returns the hyperbolic sine of x.
      """
      return _check1(x, _C.sinh(x), True)
  
  def tanh(x: float) -> float:
      """
      tanh(float) -> float
  
      Returns the hyperbolic tangent of x.
      """
      return _check1(x, _C.tanh(x))
  
  def acosh(x: float) -> float:
      """
      acosh(float) -> float
  
      Return the inverse hyperbolic cosine of x.
      """
      return _check1(x, _C.acosh(x))
  
  def asinh(x: float) -> float:
      """
      asinh(float) -> float
  
      Return the inverse hyperbolic sine of x.
      """
      return _check1(x, _C.asinh(x))
  
  def atanh(x: float) -> float:
      """
      atanh(float) -> float
  
      Return the inverse hyperbolic tangent of x.
      """
      return _check1(x, _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 _check2(x, y, f(x, y))
  
  def log1p(x: float) -> float:
      """
      log1p(float) -> float
  
      Return the natural logarithm of 1+x (base e).
      """
      return _check1(x, _C.log1p(x))
  
  def trunc(x: float) -> int:
      """
      trunc(float) -> int
  
      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 int(_check1(x, f(x)))
  
  def erf(x: float) -> float:
      """
      erf(float) -> float
  
      Return the error function at x.
      """
      return _check1(x, _C.erf(x))
  
  def erfc(x: float) -> float:
      """
      erfc(float) -> float
  
      Return the complementary error function at x.
      """
      return _check1(x, _C.erfc(x))
  
  def gamma(x: float) -> float:
      """
      gamma(float) -> float
  
      Return the Gamma function at x.
      """
      return _check1(x, _C.tgamma(x), True)
  
  def lgamma(x: float) -> float:
      """
      lgamma(float) -> float
  
      Return the natural logarithm of
      the absolute value of the Gamma function at x.
      """
      return _check1(x, _C.lgamma(x), True)
  
  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 _check2(x, y, _C.remainder(x, y))
  
  def _gcd2(a, b):
      a = abs(a)
      b = abs(b)
      while a:
          a, b = b % a, a
      return b
  
  def gcd(*args):
      """
      gcd(*args)
  
      returns greatest common divisor of arguments.
      """
      if staticlen(args) == 0:
          return 0
  
      res = args[0]
      T = type(res)
  
      if staticlen(args) == 1:
          return abs(res)
  
      for i in range(1, len(args)):
          if res == T(1):
              break
          res = _gcd2(res, args[i])
  
      return res
  
  def lcm(*args):
      """
      lcm(*args)
  
      returns least common multiple of arguments.
      """
      def lcm2(a, b):
          return abs((a // _gcd2(a, b)) * b)
  
      if staticlen(args) == 0:
          return 1
  
      res = args[0]
      T = type(res)
  
      if staticlen(args) == 1:
          return abs(res)
  
      for i in range(1, len(args)):
          if not res:
              break
          res = lcm2(res, args[i])
  
      return res
  
  @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
      )
  
  def fsum(seq):
      def _fsum_realloc(p: Ptr[float], ps: Ptr[float], n: int, m: int):
          from internal.gc import realloc, sizeof
          v = Ptr[float]()
          m += m
          if n < m:
              if p == ps:
                  v = Ptr[float](m)
                  str.memcpy(v.as_byte(), ps.as_byte(), n * sizeof(float))
              else:
                  v = Ptr[float](realloc(p.as_byte(), m * sizeof(float), n * sizeof(float)))
          return v, m
  
      _NUM_PARTIALS: Static[int] = 32
      ps_arr = __array__[float](_NUM_PARTIALS)
      ps = ps_arr.ptr
      p = ps
      n, m = 0, _NUM_PARTIALS
      xsave, special_sum, inf_sum = 0.0, 0.0, 0.0
      hi, yr, lo = 0.0, 0.0, 0.0
  
      for item in seq:
          x = float(item)
          xsave = x
          i = 0
  
          for j in range(n):  # for y in partials
              y = p[j]
              if fabs(x) < fabs(y):
                  x, y = y, x
              hi = x + y
              yr = hi - x
              lo = y - yr
              if lo != 0.0:
                  p[i] = lo
                  i += 1
              x = hi
  
          n = i
          if x != 0.0:
              if not isfinite(x):
                  # a nonfinite x could arise either as
                  # a result of intermediate overflow, or
                  if isfinite(xsave):
                      raise OverflowError("intermediate overflow in fsum")
                  if isinf(xsave):
                      inf_sum += xsave
                  special_sum += xsave
                  # reset partials
                  n = 0
              else:
                  if n >= m:
                      p, m = _fsum_realloc(p, ps, n, m)
                  p[n] = x
                  n += 1
  
      if special_sum != 0.0:
          if isnan(inf_sum):
              raise ValueError("-inf + inf in fsum")
          else:
              return special_sum
  
      hi = 0.0
      if n > 0:
          hi = p[n - 1]
          n -= 1
          # sum_exact(ps, hi) from the top, stop when the sum becomes inexact
          while n > 0:
              x = hi
              y = p[n - 1]
              n -= 1
              # assert fabs(y) < fabs(x)
              hi = x + y
              yr = hi - x
              lo = y - yr
              if lo != 0.0:
                  break
  
          # Make half-even rounding work across multiple partials.
          # Needed so that sum([1e-16, 1, 1e16]) will round-up the last
          # digit to two instead of down to zero (the 1e-16 makes the 1
          # slightly closer to two).  With a potential 1 ULP rounding
          # error fixed-up, math.fsum() can guarantee commutativity.
          if n > 0 and ((lo < 0.0 and p[n-1] < 0.0) or (lo > 0.0 and p[n-1] > 0.0)):
              y = lo * 2.0
              x = hi + y
              yr = x - hi
              if y == yr:
                  hi = x
  
      return hi
  
  def prod(iterable, start = 1):
      def prod_generator(iterable: Generator[T], start, T: type):
          if T is float:
              result = float(start)
          else:
              result = start
  
          for a in iterable:
              result *= a
          return result
  
      def prod_tuple(iterable, start):
          if staticlen(iterable) == 0:
              return start
          else:
              return prod(iterable[1:], start=(start * iterable[0]))
  
      if isinstance(iterable, Tuple):
          return prod_tuple(iterable, start)
      else:
          return prod_generator(iterable, start)
  
  # 32-bit float ops
  
  e32 = float32(e)
  pi32 = float32(pi)
  tau32 = float32(tau)
  
  inf32 = float32(inf)
  nan32 = float32(nan)
  
  @overload
  def isnan(x: float32) -> bool:
      """
      isnan(float32) -> bool
  
      Return True if float arg is a NaN, else False.
      """
      @pure
      @llvm
      def f(x: float32) -> bool:
          %y = fcmp uno float %x, 0.000000e+00
          %z = zext i1 %y to i8
          ret i8 %z
  
      return f(x)
  
  @overload
  def isinf(x: float32) -> bool:
      """
      isinf(float32) -> bool:
  
      Return True if float arg is an INF, else False.
      """
      @pure
      @llvm
      def f(x: float32) -> bool:
          declare float @llvm.fabs.f32(float)
          %a = call float @llvm.fabs.f32(float %x)
          %b = fcmp oeq float %a, 0x7FF0000000000000
          %c = zext i1 %b to i8
          ret i8 %c
  
      return f(x)
  
  @overload
  def isfinite(x: float32) -> bool:
      """
      isfinite(float32) -> bool
  
      Return True if x is neither an infinity nor a NaN,
      and False otherwise.
      """
      return not (isnan(x) or isinf(x))
  
  @overload
  def ceil(x: float32) -> int:
      """
      ceil(float32) -> int
  
      Return the ceiling of x as an Integral.
      This is the smallest integer >= x.
      """
      @pure
      @llvm
      def f(x: float32) -> float32:
          declare float @llvm.ceil.f32(float)
          %y = call float @llvm.ceil.f32(float %x)
          ret float %y
  
      return int(f(x))
  
  @overload
  def floor(x: float32) -> int:
      """
      floor(float32) -> int
  
      Return the floor of x as an Integral.
      This is the largest integer <= x.
      """
      @pure
      @llvm
      def f(x: float32) -> float32:
          declare float @llvm.floor.f32(float)
          %y = call float @llvm.floor.f32(float %x)
          ret float %y
  
      return int(f(x))
  
  @overload
  def fabs(x: float32) -> float32:
      """
      fabs(float32) -> float32
  
      Returns the absolute value of a float32ing point number.
      """
      @pure
      @llvm
      def f(x: float32) -> float32:
          declare float @llvm.fabs.f32(float)
          %y = call float @llvm.fabs.f32(float %x)
          ret float %y
  
      return f(x)
  
  @overload
  def fmod(x: float32, y: float32) -> float32:
      """
      fmod(float32, float32) -> float32
  
      Returns the remainder of x divided by y.
      """
      @pure
      @llvm
      def f(x: float32, y: float32) -> float32:
          %z = frem float %x, %y
          ret float %z
  
      return f(x, y)
  
  @overload
  def exp(x: float32) -> float32:
      """
      exp(float32) -> float32
  
      Returns the value of e raised to the xth power.
      """
      @pure
      @llvm
      def f(x: float32) -> float32:
          declare float @llvm.exp.f32(float)
          %y = call float @llvm.exp.f32(float %x)
          ret float %y
  
      return f(x)
  
  @overload
  def expm1(x: float32) -> float32:
      """
      expm1(float32) -> float32
  
      Return e raised to the power x, minus 1. expm1 provides
      a way to compute this quantity to full precision.
      """
      return _C.expm1f(x)
  
  @overload
  def ldexp(x: float32, i: int) -> float32:
      """
      ldexp(float32, int) -> float32
  
      Returns x multiplied by 2 raised to the power of exponent.
      """
      return _C.ldexpf(x, i32(i))
  
  @overload
  def log(x: float32, base: float32 = e32) -> float32:
      """
      log(float32) -> float32
  
      Returns the natural logarithm (base-e logarithm) of x.
      """
      @pure
      @llvm
      def f(x: float32) -> float32:
          declare float @llvm.log.f32(float)
          %y = call float @llvm.log.f32(float %x)
          ret float %y
  
      if base == e32:
          return f(x)
      else:
          return f(x) / f(base)
  
  @overload
  def log2(x: float32) -> float32:
      """
      log2(float32) -> float32
  
      Return the base-2 logarithm of x.
      """
      @pure
      @llvm
      def f(x: float32) -> float32:
          declare float @llvm.log2.f32(float)
          %y = call float @llvm.log2.f32(float %x)
          ret float %y
  
      return f(x)
  
  @overload
  def log10(x: float32) -> float32:
      """
      log10(float32) -> float32
  
      Returns the common logarithm (base-10 logarithm) of x.
      """
      @pure
      @llvm
      def f(x: float32) -> float32:
          declare float @llvm.log10.f32(float)
          %y = call float @llvm.log10.f32(float %x)
          ret float %y
  
      return f(x)
  
  @overload
  def degrees(x: float32) -> float32:
      """
      degrees(float32) -> float32
  
      Convert angle x from radians to degrees.
      """
      radToDeg = float32(180.0) / pi32
      return x * radToDeg
  
  @overload
  def radians(x: float32) -> float32:
      """
      radians(float32) -> float32
  
      Convert angle x from degrees to radians.
      """
      degToRad = pi32 / float32(180.0)
      return x * degToRad
  
  @overload
  def sqrt(x: float32) -> float32:
      """
      sqrt(float32) -> float32
  
      Returns the square root of x.
      """
      @pure
      @llvm
      def f(x: float32) -> float32:
          declare float @llvm.sqrt.f32(float)
          %y = call float @llvm.sqrt.f32(float %x)
          ret float %y
  
      return f(x)
  
  @overload
  def pow(x: float32, y: float32) -> float32:
      """
      pow(float32, float32) -> float32
  
      Returns x raised to the power of y.
      """
      @pure
      @llvm
      def f(x: float32, y: float32) -> float32:
          declare float @llvm.pow.f32(float, float)
          %z = call float @llvm.pow.f32(float %x, float %y)
          ret float %z
  
      return f(x, y)
  
  @overload
  def acos(x: float32) -> float32:
      """
      acos(float32) -> float32
  
      Returns the arc cosine of x in radians.
      """
      return _C.acosf(x)
  
  @overload
  def asin(x: float32) -> float32:
      """
      asin(float32) -> float32
  
      Returns the arc sine of x in radians.
      """
      return _C.asinf(x)
  
  @overload
  def atan(x: float32) -> float32:
      """
      atan(float32) -> float32
  
      Returns the arc tangent of x in radians.
      """
      return _C.atanf(x)
  
  @overload
  def atan2(y: float32, x: float32) -> float32:
      """
      atan2(float32, float32) -> float32
  
      Returns the arc tangent in radians of y/x based
      on the signs of both values to determine the
      correct quadrant.
      """
      return _C.atan2f(y, x)
  
  @overload
  def cos(x: float32) -> float32:
      """
      cos(float32) -> float32
  
      Returns the cosine of a radian angle x.
      """
      @pure
      @llvm
      def f(x: float32) -> float32:
          declare float @llvm.cos.f32(float)
          %y = call float @llvm.cos.f32(float %x)
          ret float %y
  
      return f(x)
  
  @overload
  def sin(x: float32) -> float32:
      """
      sin(float32) -> float32
  
      Returns the sine of a radian angle x.
      """
      @pure
      @llvm
      def f(x: float32) -> float32:
          declare float @llvm.sin.f32(float)
          %y = call float @llvm.sin.f32(float %x)
          ret float %y
  
      return f(x)
  
  @overload
  def hypot(x: float32, y: float32) -> float32:
      """
      hypot(float32, float32) -> float32
  
      Return the Euclidean norm.
      This is the length of the vector from the
      origin to point (x, y).
      """
      return _C.hypotf(x, y)
  
  @overload
  def tan(x: float32) -> float32:
      """
      tan(float32) -> float32
  
      Return the tangent of a radian angle x.
      """
      return _C.tanf(x)
  
  @overload
  def cosh(x: float32) -> float32:
      """
      cosh(float32) -> float32
  
      Returns the hyperbolic cosine of x.
      """
      return _C.coshf(x)
  
  @overload
  def sinh(x: float32) -> float32:
      """
      sinh(float32) -> float32
  
      Returns the hyperbolic sine of x.
      """
      return _C.sinhf(x)
  
  @overload
  def tanh(x: float32) -> float32:
      """
      tanh(float32) -> float32
  
      Returns the hyperbolic tangent of x.
      """
      return _C.tanhf(x)
  
  @overload
  def acosh(x: float32) -> float32:
      """
      acosh(float32) -> float32
  
      Return the inverse hyperbolic cosine of x.
      """
      return _C.acoshf(x)
  
  @overload
  def asinh(x: float32) -> float32:
      """
      asinh(float32) -> float32
  
      Return the inverse hyperbolic sine of x.
      """
      return _C.asinhf(x)
  
  @overload
  def atanh(x: float32) -> float32:
      """
      atanh(float32) -> float32
  
      Return the inverse hyperbolic tangent of x.
      """
      return _C.atanhf(x)
  
  @overload
  def copysign(x: float32, y: float32) -> float32:
      """
      copysign(float32, float32) -> float32
  
      Return a float32 with the magnitude (absolute value) of
      x but the sign of y.
      """
      @pure
      @llvm
      def f(x: float32, y: float32) -> float32:
          declare float @llvm.copysign.f32(float, float)
          %z = call float @llvm.copysign.f32(float %x, float %y)
          ret float %z
  
      return f(x, y)
  
  @overload
  def log1p(x: float32) -> float32:
      """
      log1p(float32) -> float32
  
      Return the natural logarithm of 1+x (base e).
      """
      return _C.log1pf(x)
  
  @overload
  def trunc(x: float32) -> int:
      """
      trunc(float32) -> int
  
      Return the Real value x truncated to an Integral
      (usually an integer).
      """
      @pure
      @llvm
      def f(x: float32) -> float32:
          declare float @llvm.trunc.f32(float)
          %y = call float @llvm.trunc.f32(float %x)
          ret float %y
  
      return int(f(x))
  
  @overload
  def erf(x: float32) -> float32:
      """
      erf(float32) -> float32
  
      Return the error function at x.
      """
      return _C.erff(x)
  
  @overload
  def erfc(x: float32) -> float32:
      """
      erfc(float32) -> float32
  
      Return the complementary error function at x.
      """
      return _C.erfcf(x)
  
  @overload
  def gamma(x: float32) -> float32:
      """
      gamma(float32) -> float32
  
      Return the Gamma function at x.
      """
      return _C.tgammaf(x)
  
  @overload
  def lgamma(x: float32) -> float32:
      """
      lgamma(float32) -> float32
  
      Return the natural logarithm of
      the absolute value of the Gamma function at x.
      """
      return _C.lgammaf(x)
  
  @overload
  def remainder(x: float32, y: float32) -> float32:
      """
      remainder(float32, float32) -> float32
  
      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.remainderf(x, y)
  
  @overload
  @pure
  def frexp(x: float32) -> Tuple[float32, int]:
      """
      frexp(float32) -> Tuple[float32, 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.frexpf(float32(x), __ptr__(tmp))
      return (res, int(tmp))
  
  @overload
  @pure
  def modf(x: float32) -> Tuple[float32, float32]:
      """
      modf(float32) -> Tuple[float32, float32]
  
      The returned value is the fraction component (part after
      the decimal), and sets integer to the integer component.
      """
      tmp = float32(0.0)
      res = _C.modff(float32(x), __ptr__(tmp))
      return (res, tmp)
  
  @overload
  def isclose(a: float32, b: float32, rel_tol: float32 = float32(1e-09), abs_tol: float32 = float32(0.0)) -> bool:
      """
      isclose(float32, float32) -> 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 == inf32 or b == inf32:
          return False
  
      # NAN is not close to anything, not even itself
      if a == nan32 or b == nan32:
          return False
  
      # regular computation
      diff = fabs(b - a)
  
      return ((diff <= fabs(rel_tol * b)) or (diff <= fabs(rel_tol * a))) or (
          diff <= abs_tol
      )
  