static class · System

Math

public static class Math
Kind
static class
Namespace
System
Assembly
System.Core
Access
public, static, abstract
Source file
Math.ant

Inheritance

Base classes
Any Math

Properties

f64 PI { get; }
#

static read-only

f64 E { get; }
#

static read-only

f64 Tau { get; }
#

static read-only

Methods

Sqrt<T : INumber<T>>(T x) : T
#

static

The square root; of an integer, the largest integer whose square is at most x (ISqrt).

Sin<T : INumber<T>>(T x) : T
#

static

Cos<T : INumber<T>>(T x) : T
#

static

Tan<T : INumber<T>>(T x) : T
#

static

Asin<T : INumber<T>>(T x) : T
#

static

Acos<T : INumber<T>>(T x) : T
#

static

Atan<T : INumber<T>>(T x) : T
#

static

Atan2<T : INumber<T>>(T y, T x) : T
#

static

Exp<T : INumber<T>>(T x) : T
#

static

Log<T : INumber<T>>(T x) : T
#

static

The natural logarithm.

Log<T : INumber<T>>(T x, T newBase) : T
#

static

The logarithm in newBase; of integers, the largest power of newBase not above x (exact: 1000 in base 10 is 3, where a floating-point quotient would give 2.9999...); of an integer below 1, or in an integer base below 2, an ArgumentError (no integer says -infinity or nan).

Log10<T : INumber<T>>(T x) : T
#

static

The logarithm in base 10 (of an integer, exact, as Log(x, 10); of an integer below 1, an ArgumentError).

Log2<T : INumber<T>>(T x) : T
#

static

The logarithm in base 2 (of an integer, exact, as Log(x, 2); of an integer below 1, an ArgumentError).

Pow<T : INumber<T>>(T x, T y) : T
#

static

x to the power y; of integers with y >= 0, exact in the type (squaring, as many multiplications as y has bits), where f64 would round past 2^53.

Floor<T : INumber<T>>(T x) : T
#

static

The largest integer not above x (an integer is its own).

Ceiling<T : INumber<T>>(T x) : T
#

static

The smallest integer not below x (an integer is its own).

Truncate<T : INumber<T>>(T x) : T
#

static

The integer part, toward zero (an integer is its own).

Round<T : INumber<T>>(T x) : T
#

static

The nearest integer; halves go to the even one (an integer is its own).

Round<T : INumber<T>>(T x, i32 digits) : T
#

static

Rounded to digits decimal places (an integer is its own).

Abs<T : ISignedNumber<T>>(T x) : T
#

static

x without its sign.

Min<T : INumber<T>>(T a, T b) : T
#

static

The smaller of two numbers.

Max<T : INumber<T>>(T a, T b) : T
#

static

The larger of two numbers.

Clamp<T : INumber<T>>(T value, T low, T high) : T
#

static

value within low … high.

Sign<T : INumber<T>>(T x) : i32
#

static

-1, 0 or 1: the sign of x.

ISqrt<T : INumber<T>>(T x) : T
#

static

The largest integer whose square is at most x (x >= 0). Up to 64 bits, the f64 root corrected by division (not by squaring, which would overflow near the type's largest value). Wider, the f64 root is only close to 53 bits: from just above it Newton's method in the type comes down to the root in a few steps.

Gcd<T : INumber<T>>(T a, T b) : T
#

static

The greatest common divisor (of the numbers without their sign).

Private and internal members (39)

extern("math.sqrt") SqrtOf(f64 x) : f64
#

private static

extern("math.sin") SinOf(f64 x) : f64
#

private static

extern("math.cos") CosOf(f64 x) : f64
#

private static

extern("math.tan") TanOf(f64 x) : f64
#

private static

extern("math.asin") AsinOf(f64 x) : f64
#

private static

extern("math.acos") AcosOf(f64 x) : f64
#

private static

extern("math.atan") AtanOf(f64 x) : f64
#

private static

extern("math.atan2") Atan2Of(f64 y, f64 x) : f64
#

private static

extern("math.exp") ExpOf(f64 x) : f64
#

private static

extern("math.log") LogOf(f64 x) : f64
#

private static

extern("math.log10") Log10Of(f64 x) : f64
#

private static

extern("math.pow") PowOf(f64 x, f64 y) : f64
#

private static

extern("math.floor") FloorOf(f64 x) : f64
#

private static

extern("math.ceil") CeilingOf(f64 x) : f64
#

private static

RoundOf(f64 x) : f64
#

private static

The nearest integer; halves go to the even one.

Divisions<T : INumber<T>>(T x, T by) : T
#

private static

How many times x divides by by before it is below it (x >= 1, by >= 2): the integer logarithm.

Finite(f64 v) : bool
#

private static

Whether an f64 is neither NaN nor infinite.

Scaled<T : INumber<T>>(T x, i32 n) : T
#

private static

x times 2^n, exactly (n beyond f64's exponents too).

PowInteger<T : INumber<T>>(T x, i64 n) : T
#

private static

x to an integer power, by squaring (a negative one is the reciprocal's).

FloorWide<T : INumber<T>>(T x) : T
#

private static

The largest integer not above x: the f64-sized parts taken off one at a time (each is exact), the last below 2^52 floored and corrected by one if its f64 rounded across an integer.

CeilingWide<T : INumber<T>>(T x) : T
#

private static

RoundWide<T : INumber<T>>(T x) : T
#

private static

SqrtWide<T : INumber<T>>(T x) : T
#

private static

Newton's method from the f64 root (doubling the exact bits each step), in f64's range by an even power of two.

Bits113<T : INumber<T>>(T unit) : bool
#

private static

Whether T has f128's 113 bits (one plus 2^-112 is above one, one plus 2^-113 rounds back to it); a constant for T.

Bits237<T : INumber<T>>(T unit) : bool
#

private static

Whether T has f256's 237 bits (one plus 2^-236 is above one, one plus 2^-237 is not); a constant for T.

Ln2<T : INumber<T>>(T unit) : T
#

private static

ln 2.

PiOf<T : INumber<T>>(T unit) : T
#

private static

π.

Ln10<T : INumber<T>>(T unit) : T
#

private static

ln 10.

Ln2Series<T : INumber<T>>(T unit) : T
#

private static

ln 2 = 2 atanh(1/3), its series summed until a term no longer changes the sum.

AtanInverse<T : INumber<T>>(T unit, i32 k) : T
#

private static

atan(1/k), its series.

PiSeries<T : INumber<T>>(T unit) : T
#

private static

π by Machin's formula: 16 atan(1/5) − 4 atan(1/239).

ExpWide<T : INumber<T>>(T x) : T
#

private static

e^x: x − k ln 2 (|r| ≤ ½ ln 2), its series, times 2^k.

LogWide<T : INumber<T>>(T x) : T
#

private static

ln x: x = m·2^e (m in f64's range), Halley's method on e^y = m from the f64 logarithm, plus e ln 2.

SinSeries<T : INumber<T>>(T r) : T
#

private static

CosSeries<T : INumber<T>>(T r) : T
#

private static

SinCosWide<T : INumber<T>>(T x, i64 shift) : T
#

private static

sin x (cosine: shift 1): x − q π/2 (|r| ≤ π/4), the series of sin or cos of r by the quadrant.

AtanWide<T : INumber<T>>(T x) : T
#

private static

atan x: Newton's method on tan y = x from the f64 arctangent.

Atan2Wide<T : INumber<T>>(T y, T x) : T
#

private static

PowWide<T : INumber<T>>(T x, T y) : T
#

private static

Inherited members (5)

Source

Math as Antril, decompiled from its Larva HIR.

System.Math.ant
// System.Math — System.Core (decompiled from Larva HIR)

into namespace System
{
	public static class Math
	{
		extern("math.sqrt") SqrtOf(f64 x) : f64;

		extern("math.sin") SinOf(f64 x) : f64;

		extern("math.cos") CosOf(f64 x) : f64;

		extern("math.tan") TanOf(f64 x) : f64;

		extern("math.asin") AsinOf(f64 x) : f64;

		extern("math.acos") AcosOf(f64 x) : f64;

		extern("math.atan") AtanOf(f64 x) : f64;

		extern("math.atan2") Atan2Of(f64 y, f64 x) : f64;

		extern("math.exp") ExpOf(f64 x) : f64;

		extern("math.log") LogOf(f64 x) : f64;

		extern("math.log10") Log10Of(f64 x) : f64;

		extern("math.pow") PowOf(f64 x, f64 y) : f64;

		extern("math.floor") FloorOf(f64 x) : f64;

		extern("math.ceil") CeilingOf(f64 x) : f64;

		/// The nearest integer; halves go to the even one.
		RoundOf(f64 x) : f64
		{
			f64 low = FloorOf(x);
			f64 rest = x - low;
			if (rest > 0.5)
				return low + 1.0;
			if (rest < 0.5)
				return low;
			return FloorOf(low / 2.0) * 2.0 == low ? low : low + 1.0;
		}

		/// How many times `x` divides by `by` before it is below it (x >= 1, by >= 2): the integer logarithm.
		Divisions<T : INumber<T>>(T x, T by) : T
		{
			T count = T.Zero;
			loop (!(x < by))
			{
				x = x / by;
				count = count + T.One;
			}
			return count;
		}

		/// Whether an f64 is neither NaN nor infinite.
		Finite(f64 v) : bool => v - v == 0.0;

		/// `x` times 2^n, exactly (n beyond f64's exponents too).
		Scaled<T : INumber<T>>(T x, i32 n) : T
		{
			loop (n > 1000)
			{
				x = x * T.FromF64(1.0715086071862673E+301);
				n = n - 1000;
			}
			loop (n < -1000)
			{
				x = x * T.FromF64(9.332636185032189E-302);
				n = n + 1000;
			}
			return x * T.FromF64(PowOf(2.0, n));
		}

		/// `x` to an integer power, by squaring (a negative one is the reciprocal's).
		PowInteger<T : INumber<T>>(T x, i64 n) : T
		{
			bool inverse = n < 0;
			if (inverse)
				n = -n;
			T result = T.One;
			T factor = x;
			loop (n > 0)
			{
				if (n % 2 == 1)
					result = result * factor;
				n = n / 2;
				if (n > 0)
					factor = factor * factor;
			}
			return inverse ? T.One / result : result;
		}

		/// The largest integer not above `x`: the f64-sized parts taken off one at a time (each is exact), the last below
		/// 2^52 floored and corrected by one if its f64 rounded across an integer.
		FloorWide<T : INumber<T>>(T x) : T
		{
			if (!Finite(T.ToF64(x)))
				return x;
			T big = T.FromF64(4503599627370496.0);
			T result = T.Zero;
			T rest = x;
			loop (!(rest < big) || !(T.Zero - big < rest))
			{
				T part = T.FromF64(T.ToF64(rest));
				result = result + part;
				rest = rest - part;
			}
			T low = T.FromF64(FloorOf(T.ToF64(rest)));
			if (rest < low)
				low = low - T.One;
			else if (!(rest < low + T.One))
				low = low + T.One;
			return result + low;
		}

		CeilingWide<T : INumber<T>>(T x) : T => T.Zero - FloorWide(T.Zero - x);

		RoundWide<T : INumber<T>>(T x) : T
		{
			T two = T.One + T.One;
			T low = FloorWide(x);
			T rest = x - low;
			T half = T.One / two;
			if (half < rest)
				return low + T.One;
			if (rest < half)
				return low;
			return FloorWide(low / two) * two == low ? low : low + T.One;
		}

		/// Newton's method from the f64 root (doubling the exact bits each step), in f64's range by an even power of two.
		SqrtWide<T : INumber<T>>(T x) : T
		{
			if (!(T.Zero < x) || !Finite(T.ToF64(x)) && x == x + x)
				return T.FromF64(SqrtOf(T.ToF64(x)));
			i32 scale = 0;
			loop (!Finite(T.ToF64(x)))
			{
				x = Scaled(x, -1000);
				scale = scale + 500;
			}
			loop (T.ToF64(x) < 1E-300)
			{
				x = Scaled(x, 1000);
				scale = scale - 500;
			}
			T two = T.One + T.One;
			T root = T.FromF64(SqrtOf(T.ToF64(x)));
			loop (i32 i = 0..8)
			{
				T next = (root + x / root) / two;
				if (next == root)
					break;
				root = next;
			}
			return Scaled(root, scale);
		}

		/// Whether T has f128's 113 bits (one plus 2^-112 is above one, one plus 2^-113 rounds back to it); a constant for T.
		[Inline]
		Bits113<T : INumber<T>>(T unit) : bool
		{
			return T.One < T.One + T.FromF64(1.925929944387236E-34) && !(T.One < T.One + T.FromF64(9.62964972193618E-35));
		}

		/// Whether T has f256's 237 bits (one plus 2^-236 is above one, one plus 2^-237 is not); a constant for T.
		[Inline]
		Bits237<T : INumber<T>>(T unit) : bool
		{
			return T.One < T.One + T.FromF64(9.055679078826712E-72) && !(T.One < T.One + T.FromF64(4.527839539413356E-72));
		}

		/// ln 2.
		Ln2<T : INumber<T>>(T unit) : T
		{
			if (Bits113(unit))
				return T.FromF64(0.6931471805599453) + T.FromF64(2.3190468138462996E-17) + T.FromF64(2.8888949165808538E-34);
			if (Bits237(unit))
				return T.FromF64(0.6931471805599453) + T.FromF64(2.3190468138462996E-17) + T.FromF64(5.707708438416212E-34) + T.FromF64(-3.5824322106018114E-50) + T.FromF64(-1.3521668330131682E-66);
			return Ln2Series(unit);
		}

		/// π.
		PiOf<T : INumber<T>>(T unit) : T
		{
			if (Bits113(unit))
				return T.FromF64(3.141592653589793) + T.FromF64(1.2246467991473532E-16) + T.FromF64(-3.0814879110195774E-33);
			if (Bits237(unit))
				return T.FromF64(3.141592653589793) + T.FromF64(1.2246467991473532E-16) + T.FromF64(-2.9947698097183397E-33) + T.FromF64(1.1124542208633653E-49) + T.FromF64(5.672205704604688E-66);
			return PiSeries(unit);
		}

		/// ln 10.
		Ln10<T : INumber<T>>(T unit) : T
		{
			if (Bits113(unit))
				return T.FromF64(2.302585092994046) + T.FromF64(-2.1707562233822494E-16) + T.FromF64(-1.0785207688568521E-32);
			if (Bits237(unit))
				return T.FromF64(2.302585092994046) + T.FromF64(-2.1707562233822494E-16) + T.FromF64(-9.984262454465777E-33) + T.FromF64(-4.023357454450206E-49) + T.FromF64(1.9288994887780366E-65);
			return LogWide(T.FromF64(10.0));
		}

		/// ln 2 = 2 atanh(1/3), its series summed until a term no longer changes the sum.
		Ln2Series<T : INumber<T>>(T unit) : T
		{
			T z = T.One / T.FromF64(3.0);
			T z2 = z * z;
			T term = z;
			T sum = T.Zero;
			i32 n = 1;
			loop (i32 i = 0..2000)
			{
				T next = sum + term / T.FromF64(n);
				if (next == sum)
					break;
				sum = next;
				term = term * z2;
				n = n + 2;
			}
			return sum + sum;
		}

		/// atan(1/k), its series.
		AtanInverse<T : INumber<T>>(T unit, i32 k) : T
		{
			T z = T.One / T.FromF64(k);
			T z2 = z * z;
			T term = z;
			T sum = T.Zero;
			i32 n = 1;
			bool add = true;
			loop (i32 i = 0..2000)
			{
				T part = term / T.FromF64(n);
				T next = add ? sum + part : sum - part;
				if (next == sum)
					break;
				sum = next;
				term = term * z2;
				n = n + 2;
				add = !add;
			}
			return sum;
		}

		/// π by Machin's formula: 16 atan(1/5) − 4 atan(1/239).
		PiSeries<T : INumber<T>>(T unit) : T => T.FromF64(16.0) * AtanInverse(unit, 5) - T.FromF64(4.0) * AtanInverse(unit, 239);

		/// e^x: x − k ln 2 (|r| ≤ ½ ln 2), its series, times 2^k.
		ExpWide<T : INumber<T>>(T x) : T
		{
			f64 v = T.ToF64(x);
			if (!Finite(v) || v > 10000000.0 || v < -10000000.0)
				return T.FromF64(ExpOf(v));
			f64 k = RoundOf(v / 0.6931471805599453);
			T r = x - T.FromF64(k) * Ln2(x);
			T term = T.One;
			T sum = T.One;
			loop (i32 n = 1..1000)
			{
				term = term * r / T.FromF64(n);
				T next = sum + term;
				if (next == sum)
					break;
				sum = next;
			}
			return Scaled(sum, (i32)k);
		}

		/// ln x: x = m·2^e (m in f64's range), Halley's method on e^y = m from the f64 logarithm, plus e ln 2.
		LogWide<T : INumber<T>>(T x) : T
		{
			if (!(T.Zero < x) || !Finite(T.ToF64(x)) && x == x + x)
				return T.FromF64(LogOf(T.ToF64(x)));
			i32 e = 0;
			loop (!Finite(T.ToF64(x)))
			{
				x = Scaled(x, -1000);
				e = e + 1000;
			}
			loop (T.ToF64(x) < 1E-300)
			{
				x = Scaled(x, 1000);
				e = e - 1000;
			}
			T two = T.One + T.One;
			T y = T.FromF64(LogOf(T.ToF64(x)));
			loop (i32 i = 0..6)
			{
				T ey = ExpWide(y);
				T next = y + two * (x - ey) / (x + ey);
				if (next == y)
					break;
				y = next;
			}
			return e == 0 ? y : y + T.FromF64(e) * Ln2(x);
		}

		SinSeries<T : INumber<T>>(T r) : T
		{
			T r2 = r * r;
			T term = r;
			T sum = r;
			i32 n = 1;
			loop (i32 i = 0..1000)
			{
				term = T.Zero - term * r2 / T.FromF64(((f64)n + 1.0) * ((f64)n + 2.0));
				n = n + 2;
				T next = sum + term;
				if (next == sum)
					break;
				sum = next;
			}
			return sum;
		}

		CosSeries<T : INumber<T>>(T r) : T
		{
			T r2 = r * r;
			T term = T.One;
			T sum = T.One;
			i32 n = 0;
			loop (i32 i = 0..1000)
			{
				term = T.Zero - term * r2 / T.FromF64(((f64)n + 1.0) * ((f64)n + 2.0));
				n = n + 2;
				T next = sum + term;
				if (next == sum)
					break;
				sum = next;
			}
			return sum;
		}

		/// sin x (cosine: shift 1): x − q π/2 (|r| ≤ π/4), the series of sin or cos of r by the quadrant.
		SinCosWide<T : INumber<T>>(T x, i64 shift) : T
		{
			f64 v = T.ToF64(x);
			if (!Finite(v))
				return T.FromF64(shift == 0 ? SinOf(v) : CosOf(v));
			f64 q = RoundOf(v / 1.5707963267948966);
			T r = x - T.FromF64(q) * (PiOf(x) / (T.One + T.One));
			i64 quadrant = (((i64)q + shift) % 4 + 4) % 4;
			if (quadrant == 0)
				return SinSeries(r);
			if (quadrant == 1)
				return CosSeries(r);
			if (quadrant == 2)
				return T.Zero - SinSeries(r);
			return T.Zero - CosSeries(r);
		}

		/// atan x: Newton's method on tan y = x from the f64 arctangent.
		AtanWide<T : INumber<T>>(T x) : T
		{
			if (!Finite(T.ToF64(x)) && x == x + x || !(x == x))
				return T.FromF64(AtanOf(T.ToF64(x)));
			T y = T.FromF64(AtanOf(T.ToF64(x)));
			loop (i32 i = 0..4)
			{
				T s = SinCosWide(y, 0);
				T c = SinCosWide(y, 1);
				T next = y - c * (s - x * c);
				if (next == y)
					break;
				y = next;
			}
			return y;
		}

		Atan2Wide<T : INumber<T>>(T y, T x) : T
		{
			if (T.Zero < x)
				return AtanWide(y / x);
			T pi = PiOf(x);
			if (x < T.Zero)
				return y < T.Zero ? AtanWide(y / x) - pi : AtanWide(y / x) + pi;
			if (x == T.Zero && y == y)
				return T.Zero < y ? pi / (T.One + T.One) : y < T.Zero ? T.Zero - pi / (T.One + T.One) : T.Zero;
			return T.FromF64(Atan2Of(T.ToF64(y), T.ToF64(x)));
		}

		PowWide<T : INumber<T>>(T x, T y) : T
		{
			f64 n = T.ToF64(y);
			if (FloorWide(y) == y && Finite(n) && n < 4E+18 && n > -4E+18)
				return PowInteger(x, (i64)n);
			if (!(T.Zero < x))
				return T.FromF64(PowOf(T.ToF64(x), n));
			return ExpWide(y * LogWide(x));
		}

		public:
			/// The square root; of an integer, the largest integer whose square is at most `x` (ISqrt).
			[Inline]
			Sqrt<T : INumber<T>>(T x) : T
			{
				return T.One / (T.One + T.One) == T.Zero ? ISqrt(x) : T.One < T.One + T.FromF64(1.1102230246251565E-16) ? SqrtWide(x) : T.FromF64(SqrtOf(T.ToF64(x)));
			}

			Sin<T : INumber<T>>(T x) : T
			{
				return T.One < T.One + T.FromF64(1.1102230246251565E-16) ? SinCosWide(x, 0) : T.FromF64(SinOf(T.ToF64(x)));
			}

			Cos<T : INumber<T>>(T x) : T
			{
				return T.One < T.One + T.FromF64(1.1102230246251565E-16) ? SinCosWide(x, 1) : T.FromF64(CosOf(T.ToF64(x)));
			}

			Tan<T : INumber<T>>(T x) : T
			{
				return T.One < T.One + T.FromF64(1.1102230246251565E-16) ? SinCosWide(x, 0) / SinCosWide(x, 1) : T.FromF64(TanOf(T.ToF64(x)));
			}

			Asin<T : INumber<T>>(T x) : T
			{
				return T.One < T.One + T.FromF64(1.1102230246251565E-16) ? Atan2Wide(x, SqrtWide(T.One - x * x)) : T.FromF64(AsinOf(T.ToF64(x)));
			}

			Acos<T : INumber<T>>(T x) : T
			{
				return T.One < T.One + T.FromF64(1.1102230246251565E-16) ? Atan2Wide(SqrtWide(T.One - x * x), x) : T.FromF64(AcosOf(T.ToF64(x)));
			}

			Atan<T : INumber<T>>(T x) : T
			{
				return T.One < T.One + T.FromF64(1.1102230246251565E-16) ? AtanWide(x) : T.FromF64(AtanOf(T.ToF64(x)));
			}

			Atan2<T : INumber<T>>(T y, T x) : T
			{
				return T.One < T.One + T.FromF64(1.1102230246251565E-16) ? Atan2Wide(y, x) : T.FromF64(Atan2Of(T.ToF64(y), T.ToF64(x)));
			}

			Exp<T : INumber<T>>(T x) : T
			{
				return T.One < T.One + T.FromF64(1.1102230246251565E-16) ? ExpWide(x) : T.FromF64(ExpOf(T.ToF64(x)));
			}

			/// The natural logarithm.
			Log<T : INumber<T>>(T x) : T
			{
				return T.One < T.One + T.FromF64(1.1102230246251565E-16) ? LogWide(x) : T.FromF64(LogOf(T.ToF64(x)));
			}

			/// The logarithm in `newBase`; of integers, the largest power of `newBase` not above `x` (exact: 1000 in base
			/// 10 is 3, where a floating-point quotient would give 2.9999...); of an integer below 1, or in an integer
			/// base below 2, an ArgumentError (no integer says -infinity or nan).
			Log<T : INumber<T>>(T x, T newBase) : T
			{
				T two = T.One + T.One;
				if (T.One / two == T.Zero)
				{
					if (x < T.One || newBase < two)
						throw new ArgumentError("Math.Log: an integer's logarithm needs x >= 1 and a base >= 2");
					return Divisions(x, newBase);
				}
				if (T.One < T.One + T.FromF64(1.1102230246251565E-16))
					return LogWide(x) / LogWide(newBase);
				return T.FromF64(LogOf(T.ToF64(x)) / LogOf(T.ToF64(newBase)));
			}

			/// The logarithm in base 10 (of an integer, exact, as `Log(x, 10)`; of an integer below 1, an ArgumentError).
			Log10<T : INumber<T>>(T x) : T
			{
				if (T.One / (T.One + T.One) == T.Zero)
				{
					if (x < T.One)
						throw new ArgumentError("Math.Log10: an integer's logarithm needs x >= 1");
					return Divisions(x, T.FromF64(10.0));
				}
				if (T.One < T.One + T.FromF64(1.1102230246251565E-16))
					return LogWide(x) / Ln10(x);
				return T.FromF64(Log10Of(T.ToF64(x)));
			}

			/// The logarithm in base 2 (of an integer, exact, as `Log(x, 2)`; of an integer below 1, an ArgumentError).
			Log2<T : INumber<T>>(T x) : T
			{
				T two = T.One + T.One;
				if (T.One / two == T.Zero)
				{
					if (x < T.One)
						throw new ArgumentError("Math.Log2: an integer's logarithm needs x >= 1");
					return Divisions(x, two);
				}
				if (T.One < T.One + T.FromF64(1.1102230246251565E-16))
					return LogWide(x) / Ln2(x);
				return T.FromF64(LogOf(T.ToF64(x)) / 0.6931471805599453);
			}

			/// `x` to the power `y`; of integers with `y >= 0`, exact in the type (squaring, as many multiplications as
			/// `y` has bits), where f64 would round past 2^53.
			Pow<T : INumber<T>>(T x, T y) : T
			{
				T two = T.One + T.One;
				if (T.One / two == T.Zero && !(y < T.Zero))
				{
					T result = T.One;
					T factor = x;
					T rest = y;
					loop (T.Zero < rest)
					{
						if (rest % two == T.One)
							result = result * factor;
						rest = rest / two;
						if (T.Zero < rest)
							factor = factor * factor;
					}
					return result;
				}
				if (T.One < T.One + T.FromF64(1.1102230246251565E-16))
					return PowWide(x, y);
				return T.FromF64(PowOf(T.ToF64(x), T.ToF64(y)));
			}

			/// The largest integer not above `x` (an integer is its own).
			[Inline]
			Floor<T : INumber<T>>(T x) : T
			{
				return T.One / (T.One + T.One) == T.Zero ? x : T.One < T.One + T.FromF64(1.1102230246251565E-16) ? FloorWide(x) : T.FromF64(FloorOf(T.ToF64(x)));
			}

			/// The smallest integer not below `x` (an integer is its own).
			[Inline]
			Ceiling<T : INumber<T>>(T x) : T
			{
				return T.One / (T.One + T.One) == T.Zero ? x : T.One < T.One + T.FromF64(1.1102230246251565E-16) ? CeilingWide(x) : T.FromF64(CeilingOf(T.ToF64(x)));
			}

			/// The integer part, toward zero (an integer is its own).
			Truncate<T : INumber<T>>(T x) : T
			{
				if (T.One / (T.One + T.One) == T.Zero)
					return x;
				if (T.One < T.One + T.FromF64(1.1102230246251565E-16))
					return x < T.Zero ? CeilingWide(x) : FloorWide(x);
				f64 v = T.ToF64(x);
				if (v < 0.0)
					return T.FromF64(CeilingOf(v));
				return T.FromF64(FloorOf(v));
			}

			/// The nearest integer; halves go to the even one (an integer is its own).
			Round<T : INumber<T>>(T x) : T
			{
				return T.One / (T.One + T.One) == T.Zero ? x : T.One < T.One + T.FromF64(1.1102230246251565E-16) ? RoundWide(x) : T.FromF64(RoundOf(T.ToF64(x)));
			}

			/// Rounded to `digits` decimal places (an integer is its own).
			Round<T : INumber<T>>(T x, i32 digits) : T
			{
				if (T.One / (T.One + T.One) == T.Zero)
					return x;
				if (T.One < T.One + T.FromF64(1.1102230246251565E-16))
				{
					T scale = PowInteger(T.FromF64(10.0), digits);
					return RoundWide(x * scale) / scale;
				}
				f64 factor = PowOf(10.0, digits);
				return T.FromF64(RoundOf(T.ToF64(x) * factor) / factor);
			}

			/// `x` without its sign.
			Abs<T : ISignedNumber<T>>(T x) : T => x < T.Zero ? -x : x;

			/// The smaller of two numbers.
			Min<T : INumber<T>>(T a, T b) : T => a < b ? a : b;

			/// The larger of two numbers.
			Max<T : INumber<T>>(T a, T b) : T => b < a ? a : b;

			/// `value` within `low` … `high`.
			Clamp<T : INumber<T>>(T value, T low, T high) : T => value < low ? low : high < value ? high : value;

			/// -1, 0 or 1: the sign of `x`.
			Sign<T : INumber<T>>(T x) : i32 => x < T.Zero ? -1 : T.Zero < x ? 1 : 0;

			/// The largest integer whose square is at most `x` (x >= 0). Up to 64 bits, the f64 root corrected by division
			/// (not by squaring, which would overflow near the type's largest value). Wider, the f64 root is only close to
			/// 53 bits: from just above it Newton's method in the type comes down to the root in a few steps.
			ISqrt<T : INumber<T>>(T x) : T
			{
				T two = T.One + T.One;
				if (x < two)
					return x;
				T root = T.FromF64(FloorOf(SqrtOf(T.ToF64(x))));
				if (T.ToF64(x) > 2.028240960365167E+31)
				{
					root = root + root / T.FromF64(1099511627776.0) + T.One;
					loop (true)
					{
						T next = (root + x / root) / two;
						if (!(next < root))
							break;
						root = next;
					}
					return root;
				}
				if (root < T.One)
					root = T.One;
				loop (T.One < root && x / root < root)
					root = root - T.One;
				loop (!(x / (root + T.One) < root + T.One))
					root = root + T.One;
				return root;
			}

			/// The greatest common divisor (of the numbers without their sign).
			Gcd<T : INumber<T>>(T a, T b) : T
			{
				if (a < T.Zero)
					a = T.Zero - a;
				if (b < T.Zero)
					b = T.Zero - b;
				loop (!(b == T.Zero))
				{
					T rest = a % b;
					a = b;
					b = rest;
				}
				return a;
			}

			f64 PI
			{
				get => 3.141592653589793;
			}

			f64 E
			{
				get => 2.718281828459045;
			}

			f64 Tau
			{
				get => 6.283185307179586;
			}
	}
}
Esc