# 1 General Numeric operations.

share/lib/std/scalar/number.flx


fun zero: unit -> t = "(?1)0" ;
fun + : t * t -> t = "$1+$2" ;
fun neg : t -> t = "-$1" ; fun - : t * t -> t = "$1-$2" ; proc += : &t * t = "*$1+=$2;"; proc -= : &t * t = "*$1-=$2;"; } instance[t in numbers] FloatMultSemi1[t] { fun one: unit -> t = "(?1)1"; fun * : t * t -> t = "$1*$2"; proc *= : &t * t = "*$1*=$2;"; } instance[t in numbers] FloatRing[t] {} instance[t in ints $$\cup$$ complexes] FloatDring[t] { fun / : t * t -> t = "$1/$2"; fun % : t * t -> t = "$1%$2"; proc /= : &t * t = "*$1/=$2;"; proc %= : &t * t = "*$1%=$2;"; } instance[t in floats] FloatDring[t] { fun / : t * t -> t = "$1/$2"; fun % : t * t -> t = "fmod($1,$2)"; proc /= : &t * t = "*$1/=$2;"; proc %= : &t * t = "*$1=fmod($1,$2);";
}


# 2 Floating Numbers.

Operations on Real and Complex numbers.

share/lib/std/scalar/float_math.flx


// 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] {
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] {
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 ;  ## 2.1 Complex Constructors. share/lib/std/scalar/float_math.flx  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];  # 3 Real numbers share/lib/std/scalar/real.flx  instance[t in reals] Tord[t] { fun < : t * t -> bool = "$1<$2"; }  # 4 Floating Formats share/lib/std/scalar/float_format.flx  Functions to format floating point numbers. open class float_format { Style of formatting. default (w,d) : like C "w.dG" format fixed (w,d) : like C "w.dF" format scientific (w,d) : like C "w.dE" format union mode = | default of int * int | fixed of int * int | scientific of int * int ; Format a real number v with format m. fun fmt[t in reals] (v:t, m: mode) => match m with | default (w,p) => fmt_default(v,w,p) | fixed (w,p) => fmt_fixed(v,w,p) | scientific(w,p) => fmt_scientific(v,w,p) endmatch ; Format a complex number v in x + iy form, with format m for x and y. fun fmt[t,r with Complex[t,r]] (v:t, m: mode) => match m with | default (w,p) => fmt_default(real v,w,p) +"+"+fmt_default(imag v,w,p)+"i" | fixed (w,p) => fmt_fixed(real v,w,p)+"+"+fmt_fixed(imag v,w,p)+"i" | scientific(w,p) => fmt_scientific(real v,w,p)+"+"+fmt_scientific(imag v,w,p)+"i" endmatch ; Format default. fun fmt_default[t] : t * int * int -> string="::flx::rtl::strutil::fmt_default($a)" requires package "flx_strutil";

Format fixed.
fun fmt_fixed[t] : t * int * int -> string="::flx::rtl::strutil::fmt_fixed($a)" requires package "flx_strutil"; Format scientfic. fun fmt_scientific[t] : t * int * int -> string="::flx::rtl::strutil::fmt_scientific($a)" requires package "flx_strutil";
}

instance Str[float] {
fun xstr: float -> string = "::flx::rtl::strutil::str<#1>($1)" requires package "flx_strutil"; Default format float, also supports nan, +inf, -inf. fun str(x:float):string => if Float::isnan x then "nan" elif Float::isinf x then if x > 0.0f then "+inf" else "-inf" endif else xstr x endif ; } instance Str[double] { fun xstr: double -> string = "::flx::rtl::strutil::str<#1>($1)" requires package "flx_strutil";

Default format double, also supports nan, +inf, -inf.
fun str(x:double):string =>
if Double::isnan x then "nan"
elif Double::isinf x then
if x > 0.0 then "+inf" else "-inf" endif
else xstr x
endif
;
}

instance Str[ldouble] {
fun xstr: ldouble -> string = "::flx::rtl::strutil::str<#1>($1)" requires package "flx_strutil"; Default format long double, also supports nan, +inf, -inf. fun str(x:ldouble):string => if Ldouble::isnan x then "nan" elif Ldouble::isinf x then if x > 0.0l then "+inf" else "-inf" endif else xstr x endif ; }  # 5 Integral Promotion. share/lib/std/scalar/int.flx  typedef fun integral_promotion: TYPE -> TYPE = | #tiny => int | #utiny => int | #short => int | #ushort => int | #int => int | #uint => uint | #long => long | #ulong => ulong | #vlong => vlong | #uvlong => uvlong ;  # 6 Conversion operators. share/lib/std/scalar/int.flx  open class Tiny { ctor tiny: string = "static_cast<#0>(::std::atoi($1.c_str()))" requires Cxx_headers::cstdlib;
ctor[T in reals] tiny: T = "static_cast<#0>($1)/*int.flx: ctor*/"; } open class Short { ctor short: string = "static_cast<#0>(::std::atoi($1.c_str()))" requires Cxx_headers::cstdlib;
ctor[T in reals] short: T = "static_cast<#0>($1)/*int.flx: ctor*/"; } open class Int { ctor int: string = "static_cast<#0>(::std::atoi($1.c_str()))" requires Cxx_headers::cstdlib;
ctor[T in reals] int: T = "static_cast<#0>($1)/*int.flx: ctor*/"; ctor int : int = "($1)/*int.flx: ctor int IDENT*/";
// special hack
ctor int(x:bool)=> match x with | true => 1 | false => 0 endmatch;
}

open class Long
{
ctor long: string = "static_cast<#0>(::std::atoi($1.c_str()))" requires Cxx_headers::cstdlib; ctor[T in reals] long: T = "static_cast<#0>($1)/*int.flx: ctor*/";
}

open class Vlong
{
ctor vlong: string = "static_cast<#0>(::std::atoi($1.c_str()))" requires Cxx_headers::cstdlib; ctor[T in reals] vlong: T = "static_cast<#0>($1)/*int.flx: ctor*/";
}

open class Utiny
{
ctor utiny: string = "static_cast<#0>(::std::atoi($1.c_str()))" requires Cxx_headers::cstdlib; ctor[T in reals] utiny: T = "static_cast<#0>($1)/*int.flx: ctor*/";
}

open class Ushort
{
ctor ushort: string = "static_cast<#0>(::std::atoi($1.c_str()))" requires Cxx_headers::cstdlib; ctor[T in reals] ushort: T = "static_cast<#0>($1)/*int.flx: ctor*/";
}

open class Uint
{
ctor uint: string = "static_cast<#0>(::std::atoi($1.c_str()))" requires Cxx_headers::cstdlib; ctor[T in reals] uint: T = "static_cast<#0>($1)/*int.flx: ctor*/";
}

open class Ulong
{
ctor ulong: string = "static_cast<#0>(::std::atoi($1.c_str()))" requires Cxx_headers::cstdlib; ctor[T in reals] ulong: T = "static_cast<#0>($1)/*int.flx: ctor*/";
}

open class Uvlong
{
ctor uvlong: string = "static_cast<#0>(::std::atoi($1.c_str()))" requires Cxx_headers::cstdlib; ctor[T in reals] uvlong: T = "static_cast<#0>($1)/*int.flx: ctor*/";
}

open class Int8
{
ctor int8: string = "static_cast<#0>(::std::atoi($1.c_str()))" requires Cxx_headers::cstdlib; ctor[T in reals] int8: T = "static_cast<#0>($1)/*int.flx: ctor*/";
}

open class Int16
{
ctor int16: string = "static_cast<#0>(::std::atoi($1.c_str()))" requires Cxx_headers::cstdlib; ctor[T in reals] int16: T = "static_cast<#0>($1)/*int.flx: ctor*/";
}

open class Int32
{
ctor int32: string = "static_cast<#0>(::std::atoi($1.c_str()))" requires Cxx_headers::cstdlib; ctor[T in reals] int32: T = "static_cast<#0>($1)/*int.flx: ctor*/";
}

open class Int64
{
ctor int64: string = "static_cast<#0>(::std::atoi($1.c_str()))" requires Cxx_headers::cstdlib; ctor[T in reals] int64: T = "static_cast<#0>($1)/*int.flx: ctor*/";
}

open class Uint8
{
ctor uint8: string = "static_cast<#0>(::std::atoi($1.c_str()))" requires Cxx_headers::cstdlib; ctor[T in reals] uint8: T = "static_cast<#0>($1)/*int.flx: ctor*/";
}

open class Uint16
{
ctor uint16: string = "static_cast<#0>(::std::atoi($1.c_str()))" requires Cxx_headers::cstdlib; ctor[T in reals] uint16: T = "static_cast<#0>($1)/*int.flx: ctor*/";
}

open class Uint32
{
ctor uint32: string = "static_cast<#0>(::std::atoi($1.c_str()))" requires Cxx_headers::cstdlib; ctor[T in reals] uint32: T = "static_cast<#0>($1)/*int.flx: ctor*/";
}

open class Uint64
{
ctor uint64: string = "static_cast<#0>(::std::atoi($1.c_str()))" requires Cxx_headers::cstdlib; ctor[T in reals] uint64: T = "static_cast<#0>($1)/*int.flx: ctor*/";
}

open class Size
{
ctor size: string = "static_cast<#0>(::std::atoi($1.c_str()))" requires Cxx_headers::cstdlib; ctor[T in reals] size: T = "static_cast<#0>($1)/*int.flx: ctor size from #0*/";
ctor size: size = "($1)/*int.flx: ctor size IDENT*/"; // special overrides so s.len - 1 works fun - : size * int -> size = "$1-$2"; fun + : size * int -> size = "$1+$2"; } open class Ptrdiff { ctor ptrdiff: string = "static_cast<#0>(::std::atoi($1.c_str()))" requires Cxx_headers::cstdlib;
ctor[T in reals] ptrdiff: T = "static_cast<#0>($1)/*int.flx: ctor*/"; } open class Intptr { ctor intptr: string = "static_cast<#0>(::std::atoi($1.c_str()))" requires Cxx_headers::cstdlib;
ctor[T in reals] intptr: T = "static_cast<#0>($1)/*int.flx: ctor*/"; } open class Uintptr { ctor uintptr: string = "static_cast<#0>(::std::atoi($1.c_str()))" requires Cxx_headers::cstdlib;
ctor[T in reals] uintptr: T = "static_cast<#0>($1)/*int.flx: ctor*/"; } open class Intmax { ctor intmax: string = "static_cast<#0>(::std::atoi($1.c_str()))" requires Cxx_headers::cstdlib;
ctor[T in reals] intmax: T = "static_cast<#0>($1)/*int.flx: ctor*/"; } open class Uintmax { ctor uintmax: string = "static_cast<#0>(::std::atoi($1.c_str()))" requires Cxx_headers::cstdlib;
ctor[T in reals] uintmax: T = "static_cast<#0>($1)/*int.flx: ctor*/"; }  # 7 Convert to decimal string. share/lib/std/scalar/int.flx  instance Str[tiny] { fun str: tiny -> string = "::flx::rtl::strutil::str<int>($1)" requires package "flx_strutil";
}

instance Str[utiny] {
fun str: utiny -> string = "::flx::rtl::strutil::str<unsigned int>($1)" requires package "flx_strutil"; } instance [ T in short $$\cup$$ ushort $$\cup$$ int $$\cup$$ uint $$\cup$$ long $$\cup$$ ulong $$\cup$$ vlong $$\cup$$ uvlong $$\cup$$ exact_ints $$\cup$$ weird_sints $$\cup$$ weird_uints ] Str[T] { fun str: T -> string = "::flx::rtl::strutil::str<#1>($1)" requires package "flx_strutil";
}



# 8 Convert to lexical string.

share/lib/std/scalar/int.flx

  instance Repr[tiny]   { fun repr[with Str[tiny]]   (t:tiny)   : string => (str t) + "t";  }
instance Repr[short]  { fun repr[with Str[short]]  (t:short)  : string => (str t) + "s";  }
instance Repr[int]   { fun repr[with Str[int]]   (t:int)   : string => (str t) + "";  }
instance Repr[long]   { fun repr[with Str[long]]   (t:long)   : string => (str t) + "l";  }
instance Repr[vlong]  { fun repr[with Str[vlong]]  (t:vlong)  : string => (str t) + "v";  }
instance Repr[int8]  { fun repr[with Str[int8]]  (t:int8)  : string => (str t) + "i8";  }
instance Repr[int16]  { fun repr[with Str[int16]]  (t:int16)  : string => (str t) + "i16";  }
instance Repr[int32]  { fun repr[with Str[int32]]  (t:int32)  : string => (str t) + "i32";  }
instance Repr[int64]  { fun repr[with Str[int64]]  (t:int64)  : string => (str t) + "i64";  }
instance Repr[intmax]  { fun repr[with Str[intmax]]  (t:intmax)  : string => (str t) + "j";  }
instance Repr[intptr]  { fun repr[with Str[intptr]]  (t:intptr)  : string => (str t) + "p";  }
instance Repr[ptrdiff]  { fun repr[with Str[ptrdiff]]  (t:ptrdiff)  : string => (str t) + "d";  }

instance Repr[utiny]  { fun repr[with Str[utiny]]  (t:utiny)  : string => (str t) + "ut"; }
instance Repr[ushort] { fun repr[with Str[ushort]] (t:ushort) : string => (str t) + "us"; }
instance Repr[uint]   { fun repr[with Str[uint]]   (t:uint)   : string => (str t) + "u";  }
instance Repr[ulong]  { fun repr[with Str[ulong]]  (t:ulong)  : string => (str t) + "ul"; }
instance Repr[uvlong] { fun repr[with Str[uvlong]] (t:uvlong) : string => (str t) + "uv"; }
instance Repr[uint8]  { fun repr[with Str[uint8]]  (t:uint8)  : string => (str t) + "u8";  }
instance Repr[uint16]  { fun repr[with Str[uint16]]  (t:uint16)  : string => (str t) + "u16";  }
instance Repr[uint32]  { fun repr[with Str[uint32]]  (t:uint32)  : string => (str t) + "u32";  }
instance Repr[uint64]  { fun repr[with Str[uint64]]  (t:uint64)  : string => (str t) + "u64";  }
instance Repr[size]  { fun repr[with Str[size]]  (t:size)  : string => (str t) + "uz";  }
instance Repr[uintmax]  { fun repr[with Str[uintmax]]  (t:uintmax)  : string => (str t) + "uj";  }
instance Repr[uintptr]  { fun repr[with Str[uintptr]]  (t:uintptr)  : string => (str t) + "up";  }



# 9 Methods of integers

share/lib/std/scalar/int.flx

  instance[t in ints] Addgrp[t] {}
instance[t in ints] Ring[t] {}
instance[t in ints] MultSemi1[t] {}
instance[t in ints] Dring[t] {}

instance [t in uints] Bits [t] {
fun \^ : t * t -> t = "(?1)($1^$2)";
fun \| : t * t -> t = "(?1)($1|$2)";
fun \& : t * t -> t = "(?1)($1&$2)";

// note: the cast is essential to ensure ~1tu is 254tu
fun ~ : t -> t = "(?1)~$1"; proc ^= : &t * t = "*$1^=$2;"; proc |= : &t * t = "*$1|=$2;"; proc &= : &t * t = "*$1&=$2;"; } instance[t in ints] Forward[t] { fun succ: t -> t = "$1+1";
proc pre_incr: &t = "++*$1;"; proc post_incr: &t = "(*$1)++;";
}

instance[t in ints] Bidirectional[t] {
fun pred: t -> t = "$1-1"; proc pre_decr: &t = "--*$1;";
}



# 11 Methods of unsigned integers

share/lib/std/scalar/int.flx

  instance[t in uints] Unsigned_integer[t] {}



# 12 Make functions accessible without qualification

share/lib/std/scalar/int.flx

  //open[T in sints] Signed_integer[T];
open Signed_integer[tiny];
open Signed_integer[short];
open Signed_integer[int];
open Signed_integer[long];
open Signed_integer[vlong];
open Signed_integer[int8];
open Signed_integer[int16];
open Signed_integer[int32];
open Signed_integer[int64];
open Signed_integer[intmax];
open Signed_integer[ptrdiff];
open Signed_integer[intptr];

//open[T in uints] Unsigned_integer[T];
open Unsigned_integer[utiny];
open Unsigned_integer[ushort];
open Unsigned_integer[uint];
open Unsigned_integer[ulong];
open Unsigned_integer[uvlong];
open Unsigned_integer[uint8];
open Unsigned_integer[uint16];
open Unsigned_integer[uint32];
open Unsigned_integer[uint64];
open Unsigned_integer[uintmax];
open Unsigned_integer[size];
open Unsigned_integer[uintptr];



# 13 Quaternions

share/lib/std/scalar/quaternion.flx


class Quaternion
{
type quaternion = new double ^ 4;
ctor quaternion (x:double^4) => _make_quaternion x;
private typedef q = quaternion;
fun r(x:q)=> (_repr_ x) . 0;
fun i(x:q)=> (_repr_ x) . 1;
fun j(x:q)=> (_repr_ x) . 2;
fun k(x:q)=> (_repr_ x) . 3;

ctor q (x:double) => quaternion (x,0.0,0.0,0.0);

fun + (a:q,b:q):q =>
quaternion (a.r+ b.r, a.i + b.i, a.j + b.j, a.k+b.k)
;

fun * (a:q, b:q):q =>
quaternion (
a.r * b.r - a.i * b.i - a.j * b.j - a.k * b.k,
a.r * b.i + a.i * b.r + a.j * b.k - a.k * b.j,
a.r * b.j - a.i * b.k + a.j * b.r - a.k * b.i,
a.r * b.k + a.i * b.j - a.j * b.i + a.k * b.r
)
;

fun conj (a:q):q => quaternion (a.r, -a.i, -a.j, -a.k);
fun norm (a:q):double => sqrt (a.r * a.r + a.i * a.i + a.j * a.j +a.k * a.k);

fun * (a:q, b: double):q => quaternion (a.r * b, a.i * b, a.j * b, a.k * b);
fun * (a: double, b:q):q => a * b;

fun reciprocal (a:q):q => let n = norm a in conj a * (1.0/ (n * n));

// add more later, generalise scalar type
// Later, GET RID of complex and quaternions
// by introducing typeclasses for arbitrary R-modules
}



# 14 Random number generation

share/lib/std/random.flx


class Random {
private type random_device = "::std::random_device*"
private type random_engine = "::std::default_random_engine*"
private ctor random_device: 1 = "new ::std::random_device{}";
private ctor random_engine: random_device =
"new ::std::default_random_engine{(*$1)()}"; private gen generate_canonical: random_engine -> double = "::std::generate_canonical<double,\ ::std::numeric_limits<float>::digits>(*$1)"

private struct random_ctl {
rd: random_device;
e: random_engine;
}
type random = new random_ctl;
ctor random() => let rd = #random_device in
_make_random$random_ctl (rd, rd.random_engine); private gen range[I in ints]: random_engine * I * I -> I = "::std::uniform_int_distribution<decltype($2)>{$2,$3-1}(*\$1)";
gen range[I in ints](r: random)(start: I, stop: I) =>
range (r._repr_.e, start, stop);
gen range[I in ints](r: random)(stop: I): I =>
r.range (C_hack::cast[I] 0, stop);

gen randint[I in ints with FloatAddgrp[I]](r: random)(start: I, stop: I) =>
r.range (start, stop+C_hack::cast[I] 1);

gen choice[T,S with ArrayValue[S,T]](r: random)(seq: S): T =>
unsafe_get (seq, r.range seq.len);

gen randflt(r: random) => r._repr_.e.generate_canonical;

proc shuffle[T,S with ArrayObject[S,T]](r: random)(seq: S) {
for var i in 0zu upto seq.len - 2 do
j := r.randint (0zu, i);
ei := unsafe_get (seq, i);
ej := unsafe_get (seq, j);
unsafe_set (seq, i, ej);
unsafe_set (seq, j, ei);
done
}
}