#line 45 "/home/travis/build/felix-lang/felix/src/packages/numbers.fdoc"
  
  // note: has to be called Fcomplex to avoid clash with class Complex
  
  // Note: ideally we'd use constrained polymorphism for the instances..
  // saves typing it all out so many times
  open class Floatinf
  {
     const FINFINITY : float = "INFINITY" requires C99_headers::math_h;
  }
  
  open class Doubleinf
  {
     const DINFINITY : double = "(double)INFINITY" requires C99_headers::math_h;
  }
  
  open class Ldoubleinf
  {
     const LINFINITY : ldouble = "(long double)INFINITY" requires C99_headers::math_h;
  }
  
  
  
  
  open class Fcomplex
  {
    ctor[t in reals] fcomplex : t * t = "::std::complex<float>($1,$2)";
    ctor[t in reals] fcomplex : t = "::std::complex<float>($1,0)";
    instance Str[fcomplex] {
      fun str (z:fcomplex) => str(real z) + "+" + str(imag z)+"i";
    }
  }
  
  open class Dcomplex
  {
    ctor[t in reals] dcomplex : t * t = "::std::complex<double>($1,$2)";
    ctor[t in reals] dcomplex : t = "::std::complex<double>($1,0)";
    instance Str[dcomplex] {
      fun str (z:dcomplex) => str(real z) + "+" + str(imag z)+"i";
    }
  }
  
  open class Lcomplex
  {
    ctor[t in reals] lcomplex : t * t = "::std::complex<long double>($1,$2)";
    ctor[t in reals] lcomplex : t = "::std::complex<long double>($1,0)";
    instance Str[lcomplex] {
      fun str (z:lcomplex) => str(real z) + "+" + str(imag z)+"i";
    }
  }
  
  instance[t in floats] Complex[complex[t],t] {
    fun real : complex[t] -> t = "real($1)";
    fun imag : complex[t] -> t = "imag($1)";
    fun abs: complex[t] -> t = "abs($1)";
    fun arg : complex[t] -> t = "arg($1)";
    fun neg : complex[t] -> complex[t] = "-$1";
    fun + : complex[t] * complex[t] -> complex[t] = "$1+$2";
    fun - : complex[t] * complex[t] -> complex[t] = "$1-$2";
    fun * : complex[t] * complex[t] -> complex[t] = "$1*$2";
    fun / : complex[t] * complex[t] -> complex[t] = "$1/$2";
    fun + : complex[t] * t -> complex[t] = "$1+$2";
    fun - : complex[t] * t -> complex[t] = "$1-$2";
    fun * : complex[t] * t -> complex[t] = "$1*$2";
    fun / : complex[t] * t -> complex[t] = "$1/$2";
    fun + : t * complex[t] -> complex[t] = "$1+$2";
    fun - : t * complex[t] -> complex[t] = "$1-$2";
    fun * : t * complex[t] -> complex[t] = "$1*$2";
    fun / : t * complex[t] -> complex[t] = "$1/$2";
    fun zero: 1 -> complex[t] = "::std::complex<?1>(0.0)";
    fun one: 1 -> complex[t] = "::std::complex<?1>(1.0)";
  }
  
  instance[t in (floats  \(\cup\)  complexes)] Trig[t] {
    requires Cxx_headers::cmath;
    fun sin: t -> t = "::std::sin($1)";
    fun cos: t -> t = "::std::cos($1)";
    fun tan: t -> t = "::std::tan($1)";
    fun asin: t -> t = "::std::asin($1)";
    fun acos: t -> t = "::std::acos($1)";
    fun atan: t -> t = "::std::atan($1)";
    fun sinh: t -> t = "::std::sinh($1)";
    fun cosh: t -> t = "::std::cosh($1)";
    fun tanh: t -> t = "::std::tanh($1)";
    fun asinh: t -> t = "::std::asinh($1)";
    fun acosh: t -> t = "::std::acosh($1)";
    fun atanh: t -> t = "::std::atanh($1)";
    fun exp: t -> t = "::std::exp($1)";
    fun log: t -> t = "::std::log($1)";
    fun pow: t * t -> t = "::std::pow($1,$2)";
  }
  
  instance[t in floats] Real[t] {
    requires Cxx_headers::cmath;
    fun abs: t -> t = "::std::abs($1)";
    fun log10: t -> t = "::std::log10($1)";
    fun sqrt: t -> t = "::std::sqrt($1)";
    fun ceil: t -> t = "::std::ceil($1)";
    fun floor: t -> t = "::std::floor($1)";
    fun trunc: t -> t = "::std::trunc($1)";
    fun embed: int -> t = "(?1)($1)";
  }
  
  class CartComplex[r] {
    typedef t = complex[r];
    inherit Complex[t,r];
  }
  
  typedef complex[t in floats] = typematch t with
    | float => fcomplex
    | double => dcomplex
    | ldouble => lcomplex
    endmatch
  ;
  
  #line 161 "/home/travis/build/felix-lang/felix/src/packages/numbers.fdoc"
  
  ctor complex[float] (x:float, y:float) => fcomplex(x,y);
  ctor complex[double] (x:double, y:double) => dcomplex(x,y);
  ctor complex[ldouble] (x:ldouble, y:ldouble) => lcomplex(x,y);
  
  ctor complex[float] (x:float) => fcomplex(x,0.0f);
  ctor complex[double] (x:double) => dcomplex(x,0.0);
  ctor complex[ldouble] (x:ldouble) => lcomplex(x,0.0l);
  
  typedef polar[t in floats] = complex[t];
  ctor[t in floats] polar[t] : t * t = "::std::polar($1,$2)";
  
  
  instance[r in floats] CartComplex[r] {}
  
  open Real[float];
  open Real[double];
  open Real[ldouble];
  open Complex[fcomplex, float];
  open Complex[dcomplex, double];
  open Complex[lcomplex, ldouble];
  open CartComplex[float];
  open CartComplex[double];
  open CartComplex[ldouble];