Added easings. Move of math to own folder.

This commit is contained in:
Christoffer Lerno
2023-01-19 22:44:15 +01:00
committed by Christoffer Lerno
parent 92507ee388
commit e09628b664
9 changed files with 206 additions and 2 deletions

510
lib/std/math/math.c3 Normal file
View File

@@ -0,0 +1,510 @@
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::math;
import std::math::complex;
// TODO Define these using quad precision.
const E = 2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466;
const LOG2E = 1.44269504088896340735992468100189214; // log2(e)
const LOG10E = 0.434294481903251827651128918916605082; // log10(e)
const LN2 = 0.693147180559945309417232121458176568; // ln(2)
const LN10 = 2.30258509299404568401799145468436421; // ln(10)
const PI = 3.14159265358979323846264338327950288419716939937510; // pi
const PI_2 = 1.57079632679489661923132169163975144; // pi / 2
const PI_4 = 0.785398163397448309615660845819875721; // pi / 4
const DIV_PI = 0.318309886183790671537767526745028724; // 1 / pi
const DIV_2_PI = 0.636619772367581343075535053490057448; // 2 / pi
const DIV_2_SQRTPI = 1.12837916709551257389615890312154517; // 2/sqrt(pi)
const SQRT2 = 1.41421356237309504880168872420969808; // sqrt(2)
const double DIV_1_SQRT2 = 0.707106781186547524400844362104849039; // 1 / sqrt(2)
const HALF_MAX = 6.5504e+4;
const HALF_MIN = 6.103515625e-5;
const HALF_DENORM_MIN = 5.9604644775390625e-8;
const HALF_DIG = 3;
const HALF_DEC_DIGITS = 5;
const HALF_MANT_DIG = 11;
const HALF_MAX_10_EXP = 4;
const HALF_MIN_10_EXP = -4;
const HALF_MAX_EXP = 16;
const HALF_MIN_EXP = -13;
const HALF_EPSILON = 9.765625e-4;
const FLOAT_MAX = 0x1.fffffep+127;
const FLOAT_MIN = 1.17549435e-38;
const FLOAT_DENORM_MIN = 1.40129846432481707092e-45;
const FLOAT_DIG = 6;
const FLOAT_DEC_DIGITS = 9;
const FLOAT_MANT_DIG = 24;
const FLOAT_MAX_10_EXP = 38;
const FLOAT_MIN_10_EXP = -37;
const FLOAT_MAX_EXP = 128;
const FLOAT_MIN_EXP = -125;
const FLOAT_EPSILON = 1.1920928955078125e-07;
const DOUBLE_MAX = 1.79769313486231570815e+308;
const DOUBLE_MIN = 2.2250738585072014e-308;
const DOUBLE_DENORM_MIN = 4.94065645841246544177e-324;
const DOUBLE_DIG = 15;
const DOUBLE_DEC_DIGITS = 17;
const DOUBLE_MANT_DIG = 53;
const DOUBLE_MAX_10_EXP = 308;
const DOUBLE_MIN_10_EXP = -307;
const DOUBLE_MAX_EXP = 1024;
const DOUBLE_MIN_EXP = -1021;
const DOUBLE_EPSILON = 2.22044604925031308085e-16;
const QUAD_MANT_DIG = 113;
/*
const QUAD_MAX = 1.18973149535723176508575932662800702e+4932;
const QUAD_MIN = 3.36210314311209350626267781732175260e-4932;
const QUAD_DENORM_MIN = 6.47517511943802511092443895822764655e-4966;
const QUAD_DIG = 33;
const QUAD_DEC_DIGITS = 36;
const QUAD_MAX_10_EXP = 4932;
const QUAD_MIN_10_EXP = -4931;
const QUAD_MAX_EXP = 16384;
const QUAD_MIN_EXP = -16481;
const QUAD_EPSILON = 1.92592994438723585305597794258492732e-34;
*/
enum RoundingMode : int
{
TOWARD_ZERO,
TO_NEAREST,
TOWARD_INFINITY,
TOWARD_NEG_INFINITY
}
define Complex32 = Complex<float>;
define Complex64 = Complex<double>;
/**
* @require types::is_numerical($typeof(x)) `The input must be a numerical value or numerical vector`
**/
macro abs(x) = $$abs(x);
/**
* @require values::@is_int(x) `The input must be an integer`
**/
macro sign(x)
{
if (!x) return ($typeof(x))0;
return ($typeof(x))(x < 0 ? -1 : 1);
}
$if (env::COMPILER_LIBC_AVAILABLE):
extern fn double _atan(double x) @extname("atan");
extern fn float _atanf(float x) @extname("atanf");
extern fn double _atan2(double x) @extname("atan2");
extern fn float _atan2f(float x) @extname("atan2f");
macro atan(x)
{
$if ($typeof(x).typeid == float.typeid):
return _atanf(x);
$else:
return _atan(x);
$endif;
}
macro atan2(x, y)
{
$if ($typeof(x).typeid == float.typeid && $typeof(y).typeid == float.typeid):
return _atan2f(x);
$else:
return _atan2(x);
$endif;
}
$endif;
/**
* @require values::@is_floatlike(x) `The input must be a floating point value or float vector`
**/
macro ceil(x) = $$ceil(x);
/**
* @require types::is_numerical($typeof(x)) `The input must be a numerical value or numerical vector`
* @require types::@has_same(x, lower, upper) `The input types must be equal`
**/
macro clamp(x, lower, upper) = $$max(lower, $$min(x, upper));
/**
* @require values::@is_promotable_to_floatlike(mag) `The input must be a number value or float vector`
* @require values::@is_same_vector_type(mag, sgn) `The input types must match`
**/
macro copysign(mag, sgn) = $$copysign(mag, sgn);
/**
* @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector`
**/
macro cos(x) = $$cos(x);
/**
* @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector`
**/
macro cosec(x) = 1 / sin(x);
/**
* @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector`
**/
macro cosech(x) = 2 / (exp(x) - exp(-x));
/**
* @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector`
**/
macro cosh(x) = (exp(x) + exp(-x)) / 2.0;
/**
* @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector`
**/
macro cotan(x) = cos(x) / sin(x);
/**
* @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector`
**/
macro cotanh(x) = (exp(2.0 * x) + 1.0) / (exp(2.0 * x) - 1.0);
/**
* @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector`
**/
macro exp(x) = $$exp(values::promote_int(x));
/**
* @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector`
**/
macro exp2(x) = $$exp2(values::promote_int(x));
/**
* @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector`
**/
macro floor(x) = $$floor(values::promote_int(x));
/**
* @require values::@is_promotable_to_floatlike(a) `The input must be a number or float vector`
* @require values::@is_promotable_to_floatlike(b) `The input must be a number or float vector`
* @require values::@is_promotable_to_floatlike(c) `The input must be a number or float vector`
* @require types::@is_same_vector_type(a, b) `The input types must be equal`
* @require types::@is_same_vector_type(a, c) `The input types must match`
**/
macro fma(a, b, c) = $$fma(a, b, c);
/**
* @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector`
* @require values::@is_promotable_to_floatlike(y) `The input must be a number or a float vector`
* @require types::@is_same_vector_type(x, y) `The input types must match`
**/
macro hypot(x, y) = sqrt(sqr(x) + sqr(y));
/**
* @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector`
**/
macro log(x) = $$log(values::promote_int(x));
/**
* @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector`
**/
macro log2(x) = $$log2(values::promote_int(x));
/**
* @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector`
**/
macro log10(x) = $$log10(values::promote_int(x));
/**
* @require types::is_numerical($typeof(x)) `The input must be a floating point value or float vector`
* @require types::is_same($typeof(x), $typeof(y)) `The input types must be equal`
**/
macro max(x, y, ...)
{
$if ($vacount == 0):
return $$max(x, y);
$else:
var m = $$max(x, y);
$for (var $i = 0; $i < $vacount; $i++):
m = $$max(m, $vaarg($i));
$endfor;
return m;
$endif;
}
/**
* @require types::is_numerical($typeof(x)) `The input must be a numerical value or numerical vector`
* @require types::is_same($typeof(x), $typeof(y)) `The input types must be equal`
**/
macro min(x, y, ...)
{
$if ($vacount == 0):
return $$min(x, y);
$else:
var m = $$min(x, y);
$for (var $i = 0; $i < $vacount; $i++):
m = $$min(m, $vaarg($i));
$endfor;
return m;
$endif;
}
/**
* @require types::@is_float(a) `The input must be a floating point value`
* @require types::@has_same(a, b, c) `The input types must be equal`
**/
macro muladd(a, b, c) = $$fmuladd(a, b, c);
/**
* @require values::@is_floatlike(x) `The input must be a floating point value or float vector`
**/
macro nearbyint(x) = $$nearbyint(x);
/**
* @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector`
* @require values::@convertable_to(exp, x) || values::@is_int(exp) `The input must be an integer, castable to the type of x`
**/
macro pow(x, exp)
{
$if (types::is_floatlike($typeof(exp))):
return $$pow(x, ($typeof(x))exp);
$else:
return $$pow_int(x, exp);
$endif;
}
/**
* @require values::@is_floatlike(x) `The input must be a number or a float vector`
**/
macro rint(x) = $$rint(x);
/**
* @require values::@is_floatlike(x) `The input must be a floating point value or float vector`
**/
macro round(x) = $$round(x);
/**
* @require values::@is_floatlike(x) `The input must be a floating point value or float vector`
**/
macro roundeven(x) = $$roundeven(x);
/**
* @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector`
**/
macro sec(x) = 1 / cos(x);
/**
* @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector`
**/
macro sech(x) = 2 / (exp(x) + exp(-x));
/**
* @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector`
**/
macro sin(x) = $$sin(values::promote_int(x));
/**
* @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector`
**/
macro sinh(x) = (exp(x) - exp(-x)) / 2.0;
/**
* @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector`
**/
macro sqr(x) = values::promote_int(x) * values::promote_int(x);
/**
* @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector`
**/
macro sqrt(x) = $$sqrt(values::promote_int(x));
/**
* @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector`
**/
macro tan(x) = sin(x) / cos(x);
/**
* @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector`
**/
macro tanh(x) = (exp(2.0 * x) - 1.0) / (exp(2.0 * x) + 1.0);
/**
* @require values::@is_floatlike(x) `The input must be a floating point value or float vector`
**/
macro trunc(x) = $$trunc(x);
macro float float.ceil(float x) = $$ceil(x);
macro float float.clamp(float x, float lower, float upper) = $$max(lower, $$min(x, upper));
macro float float.copysign(float mag, float sgn) = $$copysign(mag, sgn);
macro float float.floor(float x) = $$floor(x);
macro float float.fma(float a, float b, float c) = $$fma(a, b, c);
macro float float.muladd(float a, float b, float c) = $$fmuladd(a, b, c);
macro float float.nearbyint(float x) = $$nearbyint(x);
macro float float.pow(float x, exp) = pow(x, exp);
macro float float.rint(float x) = $$rint(x);
macro float float.round(float x) = $$round(x);
macro float float.roundeven(float x) = $$roundeven(x);
macro float float.trunc(float x) = $$trunc(x);
macro float float[<*>].sum(float[<*>] x, float start = 0.0) = $$reduce_fadd(x, start);
macro float float[<*>].product(float[<*>] x, float start = 1.0) = $$reduce_fmul(x, start);
macro float float[<*>].max(float[<*>] x) = $$reduce_max(x);
macro float float[<*>].min(float[<*>] x) = $$reduce_min(x);
macro float[<*>] float[<*>].ceil(float[<*>] x) = $$ceil(x);
macro float[<*>] float[<*>].clamp(float[<*>] x, float[<*>] lower, float[<*>] upper) = $$max(lower, $$min(x, upper));
macro float[<*>] float[<*>].copysign(float[<*>] mag, float[<*>] sgn) = $$copysign(mag, sgn);
macro float[<*>] float[<*>].fma(float[<*>] a, float[<*>] b, float[<*>] c) = $$fma(a, b, c);
macro float[<*>] float[<*>].floor(float[<*>] x) = $$floor(x);
macro float[<*>] float[<*>].nearbyint(float[<*>] x) = $$nearbyint(x);
macro float[<*>] float[<*>].pow(float[<*>] x, exp) = pow(x, exp);
macro float[<*>] float[<*>].rint(float[<*>] x) = $$rint(x);
macro float[<*>] float[<*>].round(float[<*>] x) = $$round(x);
macro float[<*>] float[<*>].roundeven(float[<*>] x) = $$roundeven(x);
macro float[<*>] float[<*>].trunc(float[<*>] x) = $$trunc(x);
macro double double.ceil(double x) = $$ceil(x);
macro double double.clamp(double x, double lower, double upper) = $$max(lower, $$min(x, upper));
macro double double.copysign(double mag, double sgn) = $$copysign(mag, sgn);
macro double double.floor(double x) = $$floor(x);
macro double double.fma(double a, double b, double c) = $$fma(a, b, c);
macro double double.muladd(double a, double b, double c) = $$fmuladd(a, b, c);
macro double double.nearbyint(double x) = $$nearbyint(x);
macro double double.pow(double x, exp) = pow(x, exp);
macro double double.rint(double x) = $$rint(x);
macro double double.round(double x) = $$round(x);
macro double double.roundeven(double x) = $$roundeven(x);
macro double double.trunc(double x) = $$trunc(x);
macro double double[<*>].sum(double[<*>] x, double start = 0.0) = $$reduce_fadd(x, start);
macro double double[<*>].product(double[<*>] x, double start = 1.0) = $$reduce_fmul(x, start);
macro double double[<*>].max(double[<*>] x) = $$reduce_fmax(x);
macro double double[<*>].min(double[<*>] x) = $$reduce_fmin(x);
macro double[<*>] double[<*>].ceil(double[<*>] x) = $$ceil(x);
macro double[<*>] double[<*>].clamp(double[<*>] x, double[<*>] lower, double[<*>] upper) = $$max(lower, $$min(x, upper));
macro double[<*>] double[<*>].copysign(double[<*>] mag, double[<*>] sgn) = $$copysign(mag, sgn);
macro double[<*>] double[<*>].floor(double[<*>] x) = $$floor(x);
macro double[<*>] double[<*>].fma(double[<*>] a, double[<*>] b, double[<*>] c) = $$fma(a, b, c);
macro double[<*>] double[<*>].nearbyint(double[<*>] x) = $$nearbyint(x);
macro double[<*>] double[<*>].pow(double[<*>] x, exp) = pow(x, exp);
macro double[<*>] double[<*>].rint(double[<*>] x) = $$rint(x);
macro double[<*>] double[<*>].round(double[<*>] x) = $$round(x);
macro double[<*>] double[<*>].roundeven(double[<*>] x) = $$roundeven(x);
macro double[<*>] double[<*>].trunc(double[<*>] x) = $$trunc(x);
macro ichar ichar[<*>].sum(ichar[<*>] x) = $$reduce_add(x);
macro ichar ichar[<*>].product(ichar[<*>] x) = $$reduce_mul(x);
macro ichar ichar[<*>].and(ichar[<*>] x) = $$reduce_and(x);
macro ichar ichar[<*>].or(ichar[<*>] x) = $$reduce_or(x);
macro ichar ichar[<*>].xor(ichar[<*>] x) = $$reduce_xor(x);
macro ichar ichar[<*>].max(ichar[<*>] x) = $$reduce_max(x);
macro ichar ichar[<*>].min(ichar[<*>] x) = $$reduce_min(x);
macro short short[<*>].sum(short[<*>] x) = $$reduce_add(x);
macro short short[<*>].product(short[<*>] x) = $$reduce_mul(x);
macro short short[<*>].and(short[<*>] x) = $$reduce_and(x);
macro short short[<*>].or(short[<*>] x) = $$reduce_or(x);
macro short short[<*>].xor(short[<*>] x) = $$reduce_xor(x);
macro short short[<*>].max(short[<*>] x) = $$reduce_max(x);
macro short short[<*>].min(short[<*>] x) = $$reduce_min(x);
macro bool[<*>] int[<*>].comp_lt(int[<*>] x, int[<*>] y) = $$veccomplt(x, y);
macro bool[<*>] int[<*>].comp_le(int[<*>] x, int[<*>] y) = $$veccomple(x, y);
macro bool[<*>] int[<*>].comp_eq(int[<*>] x, int[<*>] y) = $$veccompeq(x, y);
macro bool[<*>] int[<*>].comp_gt(int[<*>] x, int[<*>] y) = $$veccompgt(x, y);
macro bool[<*>] int[<*>].comp_ge(int[<*>] x, int[<*>] y) = $$veccompge(x, y);
macro bool[<*>] int[<*>].comp_ne(int[<*>] x, int[<*>] y) = $$veccompne(x, y);
macro int int[<*>].sum(int[<*>] x) = $$reduce_add(x);
macro int int[<*>].product(int[<*>] x) = $$reduce_mul(x);
macro int int[<*>].and(int[<*>] x) = $$reduce_and(x);
macro int int[<*>].or(int[<*>] x) = $$reduce_or(x);
macro int int[<*>].xor(int[<*>] x) = $$reduce_xor(x);
macro int int[<*>].max(int[<*>] x) = $$reduce_max(x);
macro int int[<*>].min(int[<*>] x) = $$reduce_min(x);
macro long long[<*>].sum(long[<*>] x) = $$reduce_add(x);
macro long long[<*>].product(long[<*>] x) = $$reduce_mul(x);
macro long long[<*>].and(long[<*>] x) = $$reduce_and(x);
macro long long[<*>].or(long[<*>] x) = $$reduce_or(x);
macro long long[<*>].xor(long[<*>] x) = $$reduce_xor(x);
macro long long[<*>].max(long[<*>] x) = $$reduce_max(x);
macro long long[<*>].min(long[<*>] x) = $$reduce_min(x);
macro int128 int128[<*>].sum(int128[<*>] x) = $$reduce_add(x);
macro int128 int128[<*>].product(int128[<*>] x) = $$reduce_mul(x);
macro int128 int128[<*>].and(int128[<*>] x) = $$reduce_and(x);
macro int128 int128[<*>].or(int128[<*>] x) = $$reduce_or(x);
macro int128 int128[<*>].xor(int128[<*>] x) = $$reduce_xor(x);
macro int128 int128[<*>].max(int128[<*>] x) = $$reduce_max(x);
macro int128 int128[<*>].min(int128[<*>] x) = $$reduce_min(x);
macro bool[<*>] bool[<*>].comp_lt(bool[<*>] x, bool[<*>] y) = $$veccomplt(x, y);
macro bool[<*>] bool[<*>].comp_le(bool[<*>] x, bool[<*>] y) = $$veccomple(x, y);
macro bool[<*>] bool[<*>].comp_eq(bool[<*>] x, bool[<*>] y) = $$veccompeq(x, y);
macro bool[<*>] bool[<*>].comp_gt(bool[<*>] x, bool[<*>] y) = $$veccompgt(x, y);
macro bool[<*>] bool[<*>].comp_ge(bool[<*>] x, bool[<*>] y) = $$veccompge(x, y);
macro bool[<*>] bool[<*>].comp_ne(bool[<*>] x, bool[<*>] y) = $$veccompne(x, y);
macro bool bool[<*>].sum(bool[<*>] x) = $$reduce_add(x);
macro bool bool[<*>].product(bool[<*>] x) = $$reduce_mul(x);
macro bool bool[<*>].and(bool[<*>] x) = $$reduce_and(x);
macro bool bool[<*>].or(bool[<*>] x) = $$reduce_or(x);
macro bool bool[<*>].xor(bool[<*>] x) = $$reduce_xor(x);
macro bool bool[<*>].max(bool[<*>] x) = $$reduce_max(x);
macro bool bool[<*>].min(bool[<*>] x) = $$reduce_min(x);
macro char char[<*>].sum(char[<*>] x) = $$reduce_add(x);
macro char char[<*>].product(char[<*>] x) = $$reduce_mul(x);
macro char char[<*>].and(char[<*>] x) = $$reduce_and(x);
macro char char[<*>].or(char[<*>] x) = $$reduce_or(x);
macro char char[<*>].xor(char[<*>] x) = $$reduce_xor(x);
macro char char[<*>].max(char[<*>] x) = $$reduce_max(x);
macro char char[<*>].min(char[<*>] x) = $$reduce_min(x);
macro ushort ushort[<*>].sum(ushort[<*>] x) = $$reduce_add(x);
macro ushort ushort[<*>].product(ushort[<*>] x) = $$reduce_mul(x);
macro ushort ushort[<*>].and(ushort[<*>] x) = $$reduce_and(x);
macro ushort ushort[<*>].or(ushort[<*>] x) = $$reduce_or(x);
macro ushort ushort[<*>].xor(ushort[<*>] x) = $$reduce_xor(x);
macro ushort ushort[<*>].max(ushort[<*>] x) = $$reduce_max(x);
macro ushort ushort[<*>].min(ushort[<*>] x) = $$reduce_min(x);
macro uint uint[<*>].sum(uint[<*>] x) = $$reduce_add(x);
macro uint uint[<*>].product(uint[<*>] x) = $$reduce_mul(x);
macro uint uint[<*>].and(uint[<*>] x) = $$reduce_and(x);
macro uint uint[<*>].or(uint[<*>] x) = $$reduce_or(x);
macro uint uint[<*>].xor(uint[<*>] x) = $$reduce_xor(x);
macro uint uint[<*>].max(uint[<*>] x) = $$reduce_max(x);
macro uint uint[<*>].min(uint[<*>] x) = $$reduce_min(x);
macro ulong ulong[<*>].sum(ulong[<*>] x) = $$reduce_add(x);
macro ulong ulong[<*>].product(ulong[<*>] x) = $$reduce_mul(x);
macro ulong ulong[<*>].and(ulong[<*>] x) = $$reduce_and(x);
macro ulong ulong[<*>].or(ulong[<*>] x) = $$reduce_or(x);
macro ulong ulong[<*>].xor(ulong[<*>] x) = $$reduce_xor(x);
macro ulong ulong[<*>].max(ulong[<*>] x) = $$reduce_max(x);
macro ulong ulong[<*>].min(ulong[<*>] x) = $$reduce_min(x);
macro uint128 uint128[<*>].sum(uint128[<*>] x) = $$reduce_add(x);
macro uint128 uint128[<*>].product(uint128[<*>] x) = $$reduce_mul(x);
macro uint128 uint128[<*>].and(uint128[<*>] x) = $$reduce_and(x);
macro uint128 uint128[<*>].or(uint128[<*>] x) = $$reduce_or(x);
macro uint128 uint128[<*>].xor(uint128[<*>] x) = $$reduce_xor(x);
macro uint128 uint128[<*>].max(uint128[<*>] x) = $$reduce_max(x);
macro uint128 uint128[<*>].min(uint128[<*>] x) = $$reduce_min(x);
/**
* @checked x & 1
*/
macro bool is_power_of_2(x)
{
return x != 0 && (x & (x - 1)) == 0;
}
macro next_power_of_2(x)
{
$typeof(x) y = 1;
while (y < x) y += y;
return y;
}

View File

@@ -0,0 +1,31 @@
module std::math::complex<Type>;
union Complex
{
struct
{
Type r, c;
}
Type[<2>] v;
}
macro Complex Complex.add(Complex a, Complex b)
{
return Complex { .v = a.v + b.v };
}
macro Complex Complex.sub(Complex a, Complex b)
{
return Complex { .v = a.v - b.v };
}
macro Complex Complex.mult(Complex a, Complex b)
{
return Complex { .r = a.r * b.r - a.c * b.c, .c = a.r * b.c + b.r * a.c };
}
fn Complex Complex.div(Complex a, Complex b)
{
Type div = b.r * b.r + b.c * b.c;
return Complex { .r = (a.r * b.r + a.c * b.c) / div, .c = (a.c * b.r - a.r * b.c) / div };
}

431
lib/std/math/math.matrix.c3 Normal file
View File

@@ -0,0 +1,431 @@
module std::math::matrix;
fault MatrixError
{
MATRIX_INVERSE_DOESNT_EXIST,
}
struct Matrix2x2
{
union
{
struct
{
float m00, m01;
float m10, m11;
}
float[4] m;
}
}
struct Matrix3x3
{
union
{
struct
{
float m00; float m01; float m02;
float m10; float m11; float m12;
float m20; float m21; float m22;
}
float[9] m;
}
}
struct Matrix4x4
{
union
{
struct
{
float m00, m01, m02, m03;
float m10, m11, m12, m13;
float m20, m21, m22, m23;
float m30, m31, m32, m33;
}
float[16] m;
}
}
fn float[<2>] Matrix2x2.apply(Matrix2x2* mat, float[<2>] vec)
{
return float[<2>] {
mat.m00 * vec[0] + mat.m01 * vec[1],
mat.m10 * vec[0] + mat.m11 * vec[1],
};
}
fn float[<3>] Matrix3x3.apply(Matrix3x3* mat, float[<3>] vec)
{
return float[<3>] {
mat.m00 * vec[0] + mat.m01 * vec[1] + mat.m02 * vec[2],
mat.m10 * vec[0] + mat.m11 * vec[1] + mat.m12 * vec[2],
mat.m20 * vec[0] + mat.m21 * vec[1] + mat.m22 * vec[2],
};
}
fn float[<4>] Matrix4x4.apply(Matrix4x4* mat, float[<4>] vec)
{
return float[<4>] {
mat.m00 * vec[0] + mat.m01 * vec[1] + mat.m02 * vec[2] + mat.m03 * vec[3],
mat.m10 * vec[0] + mat.m11 * vec[1] + mat.m12 * vec[2] + mat.m13 * vec[3],
mat.m20 * vec[0] + mat.m21 * vec[1] + mat.m22 * vec[2] + mat.m23 * vec[3],
mat.m30 * vec[0] + mat.m31 * vec[1] + mat.m32 * vec[2] + mat.m33 * vec[3],
};
}
fn Matrix2x2 Matrix2x2.mul(Matrix2x2* a, Matrix2x2 b)
{
return Matrix2x2 {
a.m00 * b.m00 + a.m01 * b.m10, a.m00 * b.m01 + a.m01 * b.m11,
a.m10 * b.m01 + a.m11 * b.m11, a.m10 * b.m01 + a.m11 * b.m11,
};
}
fn Matrix3x3 Matrix3x3.mul(Matrix3x3* a, Matrix3x3 b)
{
return Matrix3x3 {
a.m00 * b.m00 + a.m01 * b.m10 + a.m02 * b.m20,
a.m00 * b.m01 + a.m01 * b.m11 + a.m02 * b.m21,
a.m00 * b.m02 + a.m01 * b.m12 + a.m02 * b.m22,
a.m10 * b.m00 + a.m11 * b.m10 + a.m12 * b.m20,
a.m10 * b.m01 + a.m11 * b.m11 + a.m12 * b.m21,
a.m10 * b.m02 + a.m11 * b.m12 + a.m12 * b.m22,
a.m20 * b.m00 + a.m21 * b.m10 + a.m22 * b.m20,
a.m20 * b.m01 + a.m21 * b.m11 + a.m22 * b.m21,
a.m20 * b.m02 + a.m21 * b.m12 + a.m22 * b.m22,
};
}
fn Matrix4x4 Matrix4x4.mul(Matrix4x4* a, Matrix4x4 b)
{
return Matrix4x4 {
a.m00 * b.m00 + a.m01 * b.m10 + a.m02 * b.m20 + a.m03 * b.m30,
a.m00 * b.m01 + a.m01 * b.m11 + a.m02 * b.m21 + a.m03 * b.m31,
a.m00 * b.m02 + a.m01 * b.m12 + a.m02 * b.m22 + a.m03 * b.m32,
a.m00 * b.m03 + a.m01 * b.m13 + a.m02 * b.m23 + a.m03 * b.m33,
a.m10 * b.m00 + a.m11 * b.m10 + a.m12 * b.m20 + a.m13 * b.m30,
a.m10 * b.m01 + a.m11 * b.m11 + a.m12 * b.m21 + a.m13 * b.m31,
a.m10 * b.m02 + a.m11 * b.m12 + a.m12 * b.m22 + a.m13 * b.m32,
a.m10 * b.m03 + a.m11 * b.m13 + a.m12 * b.m23 + a.m13 * b.m33,
a.m20 * b.m00 + a.m21 * b.m10 + a.m22 * b.m20 + a.m23 * b.m30,
a.m20 * b.m01 + a.m21 * b.m11 + a.m22 * b.m21 + a.m23 * b.m31,
a.m20 * b.m02 + a.m21 * b.m12 + a.m22 * b.m22 + a.m23 * b.m32,
a.m20 * b.m03 + a.m21 * b.m13 + a.m22 * b.m23 + a.m23 * b.m33,
a.m30 * b.m00 + a.m31 * b.m10 + a.m32 * b.m20 + a.m33 * b.m30,
a.m30 * b.m01 + a.m31 * b.m11 + a.m32 * b.m21 + a.m33 * b.m31,
a.m30 * b.m02 + a.m31 * b.m12 + a.m32 * b.m22 + a.m33 * b.m32,
a.m30 * b.m03 + a.m31 * b.m13 + a.m32 * b.m23 + a.m33 * b.m33,
};
}
fn Matrix2x2 Matrix2x2.component_mul(Matrix2x2* mat, float s)
{
return Matrix2x2 {
mat.m00 * s, mat.m01 * s,
mat.m10 * s, mat.m11 * s,
};
}
fn Matrix3x3 Matrix3x3.component_mul(Matrix3x3* mat, float s)
{
return Matrix3x3 {
mat.m00 * s, mat.m01 * s, mat.m02 * s,
mat.m10 * s, mat.m11 * s, mat.m12 * s,
mat.m20 * s, mat.m21 * s, mat.m22 * s,
};
}
fn Matrix4x4 Matrix4x4.component_mul(Matrix4x4* mat, float s)
{
return Matrix4x4 {
mat.m00 * s, mat.m01 * s, mat.m02 * s, mat.m03 * s,
mat.m10 * s, mat.m11 * s, mat.m12 * s, mat.m13 * s,
mat.m20 * s, mat.m21 * s, mat.m22 * s, mat.m23 * s,
mat.m30 * s, mat.m31 * s, mat.m32 * s, mat.m33 * s,
};
}
fn Matrix2x2 Matrix2x2.transpose(Matrix2x2* mat)
{
return Matrix2x2 {
mat.m00, mat.m10,
mat.m01, mat.m11
};
}
fn Matrix3x3 Matrix3x3.transpose(Matrix3x3* mat)
{
return Matrix3x3 {
mat.m00, mat.m10, mat.m20,
mat.m01, mat.m11, mat.m21,
mat.m02, mat.m12, mat.m22,
};
}
fn Matrix4x4 Matrix4x4.transpose(Matrix4x4* mat)
{
return Matrix4x4 {
mat.m00, mat.m10, mat.m20, mat.m30,
mat.m01, mat.m11, mat.m21, mat.m31,
mat.m02, mat.m12, mat.m22, mat.m32,
mat.m03, mat.m13, mat.m23, mat.m33,
};
}
fn float Matrix2x2.determinant(Matrix2x2* mat)
{
return mat.m00 * mat.m11 - mat.m01 * mat.m10;
}
fn float Matrix3x3.determinant(Matrix3x3* mat)
{
return
mat.m00 * (mat.m11 * mat.m22 - mat.m21 * mat.m12) -
mat.m01 * (mat.m10 * mat.m22 - mat.m20 * mat.m12) +
mat.m02 * (mat.m10 * mat.m21 - mat.m20 * mat.m11);
}
fn float Matrix4x4.determinant(Matrix4x4* mat)
{
return
mat.m00 * (mat.m11 * (mat.m22 * mat.m33 - mat.m32 * mat.m23) -
mat.m12 * (mat.m21 * mat.m33 - mat.m31 * mat.m23) +
mat.m13 * (mat.m21 * mat.m32 - mat.m31 * mat.m22) ) -
mat.m01 * (mat.m10 * (mat.m22 * mat.m33 - mat.m32 * mat.m23) -
mat.m12 * (mat.m20 * mat.m33 - mat.m30 * mat.m23) +
mat.m13 * (mat.m20 * mat.m32 - mat.m30 * mat.m22) ) +
mat.m02 * (mat.m10 * (mat.m21 * mat.m33 - mat.m31 * mat.m23) -
mat.m11 * (mat.m20 * mat.m33 - mat.m30 * mat.m23) +
mat.m13 * (mat.m20 * mat.m31 - mat.m30 * mat.m21) ) -
mat.m03 * (mat.m10 * (mat.m21 * mat.m32 - mat.m31 * mat.m22) -
mat.m11 * (mat.m20 * mat.m32 - mat.m30 * mat.m22) +
mat.m12 * (mat.m20 * mat.m31 - mat.m30 * mat.m21) );
}
fn Matrix2x2 Matrix2x2.adjoint(Matrix2x2* mat)
{
return Matrix2x2 { mat.m00, -mat.m01, -mat.m10, mat.m11 };
}
fn Matrix3x3 Matrix3x3.adjoint(Matrix3x3* mat)
{
return Matrix3x3 {
(mat.m11 * mat.m22 - mat.m21 * mat.m12),
-(mat.m10 * mat.m22 - mat.m20 * mat.m12),
(mat.m10 * mat.m21 - mat.m20 * mat.m11),
-(mat.m01 * mat.m22 - mat.m21 * mat.m02),
(mat.m00 * mat.m22 - mat.m20 * mat.m02),
-(mat.m00 * mat.m21 - mat.m20 * mat.m01),
(mat.m01 * mat.m12 - mat.m11 * mat.m02),
-(mat.m00 * mat.m12 - mat.m10 * mat.m02),
(mat.m00 * mat.m11 - mat.m10 * mat.m01),
};
}
fn Matrix4x4 Matrix4x4.adjoint(Matrix4x4* mat)
{
return Matrix4x4 {
(mat.m11 * (mat.m22 * mat.m33 - mat.m32 * mat.m23) -
mat.m12 * (mat.m21 * mat.m33 - mat.m31 * mat.m23) +
mat.m13 * (mat.m21 * mat.m32 - mat.m31 * mat.m22)),
-(mat.m10 * (mat.m22 * mat.m33 - mat.m32 * mat.m23) -
mat.m12 * (mat.m20 * mat.m33 - mat.m30 * mat.m23) +
mat.m13 * (mat.m20 * mat.m32 - mat.m30 * mat.m22)),
(mat.m10 * (mat.m21 * mat.m33 - mat.m31 * mat.m23) -
mat.m11 * (mat.m20 * mat.m33 - mat.m30 * mat.m23) +
mat.m13 * (mat.m20 * mat.m31 - mat.m30 * mat.m21)),
-(mat.m10 * (mat.m21 * mat.m32 - mat.m31 * mat.m22) -
mat.m11 * (mat.m20 * mat.m32 - mat.m30 * mat.m22) +
mat.m12 * (mat.m20 * mat.m31 - mat.m30 * mat.m21)),
-(mat.m01 * (mat.m22 * mat.m33 - mat.m32 * mat.m23) -
mat.m02 * (mat.m21 * mat.m33 - mat.m31 * mat.m23) +
mat.m03 * (mat.m21 * mat.m32 - mat.m31 * mat.m22)),
(mat.m00 * (mat.m22 * mat.m33 - mat.m32 * mat.m23) -
mat.m02 * (mat.m20 * mat.m33 - mat.m30 * mat.m23) +
mat.m03 * (mat.m20 * mat.m32 - mat.m30 * mat.m22)),
-(mat.m00 * (mat.m21 * mat.m33 - mat.m31 * mat.m23) -
mat.m01 * (mat.m20 * mat.m33 - mat.m30 * mat.m23) +
mat.m03 * (mat.m20 * mat.m31 - mat.m30 * mat.m21)),
(mat.m00 * (mat.m21 * mat.m32 - mat.m31 * mat.m22) -
mat.m01 * (mat.m20 * mat.m32 - mat.m30 * mat.m22) +
mat.m02 * (mat.m20 * mat.m31 - mat.m30 * mat.m21)),
(mat.m01 * (mat.m12 * mat.m33 - mat.m32 * mat.m13) -
mat.m02 * (mat.m11 * mat.m33 - mat.m31 * mat.m13) +
mat.m03 * (mat.m11 * mat.m32 - mat.m31 * mat.m12)),
-(mat.m00 * (mat.m12 * mat.m33 - mat.m32 * mat.m13) -
mat.m02 * (mat.m10 * mat.m33 - mat.m30 * mat.m13) +
mat.m03 * (mat.m10 * mat.m32 - mat.m30 * mat.m12)),
(mat.m00 * (mat.m11 * mat.m33 - mat.m31 * mat.m13) -
mat.m01 * (mat.m10 * mat.m33 - mat.m30 * mat.m13) +
mat.m03 * (mat.m10 * mat.m31 - mat.m30 * mat.m11)),
-(mat.m00 * (mat.m11 * mat.m32 - mat.m31 * mat.m12) -
mat.m01 * (mat.m10 * mat.m32 - mat.m30 * mat.m12) +
mat.m02 * (mat.m10 * mat.m31 - mat.m30 * mat.m11)),
-(mat.m01 * (mat.m12 * mat.m23 - mat.m22 * mat.m13) -
mat.m02 * (mat.m11 * mat.m23 - mat.m21 * mat.m13) +
mat.m03 * (mat.m11 * mat.m22 - mat.m21 * mat.m12)),
(mat.m00 * (mat.m12 * mat.m23 - mat.m22 * mat.m13) -
mat.m02 * (mat.m10 * mat.m23 - mat.m20 * mat.m13) +
mat.m03 * (mat.m10 * mat.m22 - mat.m20 * mat.m12)),
-(mat.m00 * (mat.m11 * mat.m23 - mat.m21 * mat.m13) -
mat.m01 * (mat.m10 * mat.m23 - mat.m20 * mat.m13) +
mat.m03 * (mat.m10 * mat.m21 - mat.m20 * mat.m11)),
(mat.m00 * (mat.m11 * mat.m22 - mat.m21 * mat.m12) -
mat.m01 * (mat.m10 * mat.m22 - mat.m20 * mat.m12) +
mat.m02 * (mat.m10 * mat.m21 - mat.m20 * mat.m11)),
};
}
fn Matrix2x2! Matrix2x2.inverse(Matrix2x2* m)
{
float det = m.determinant();
if (det == 0) return MatrixError.MATRIX_INVERSE_DOESNT_EXIST!;
Matrix2x2 adj = m.adjoint();
return adj.component_mul(1 / det).transpose();
}
fn Matrix3x3! Matrix3x3.inverse(Matrix3x3* m)
{
float det = m.determinant();
if (det == 0) return MatrixError.MATRIX_INVERSE_DOESNT_EXIST!;
Matrix3x3 adj = m.adjoint();
return adj.component_mul(1 / det).transpose();
}
fn Matrix4x4! Matrix4x4.inverse(Matrix4x4* m)
{
float det = m.determinant();
if (det == 0) return MatrixError.MATRIX_INVERSE_DOESNT_EXIST!;
Matrix4x4 adj = m.adjoint();
return adj.component_mul(1 / det).transpose();
}
fn Matrix3x3 Matrix3x3.translate(Matrix3x3* m, float[<2>] v)
{
return m.mul(Matrix3x3 {
1, 0, v[0],
0, 1, v[1],
0, 0, 1,
});
}
fn Matrix4x4 Matrix4x4.translate(Matrix4x4* m, float[<3>] v)
{
return m.mul(Matrix4x4 {
1, 0, 0, v[0],
0, 1, 0, v[1],
0, 0, 1, v[2],
0, 0, 0, 1,
});
}
// r in radians
fn Matrix3x3 Matrix3x3.rotate(Matrix3x3* m, float r)
{
return m.mul(Matrix3x3 {
math::cos(r), -math::sin(r), 0,
math::sin(r), math::cos(r), 0,
0, 0, 1,
});
}
// r in radians
fn Matrix4x4 Matrix4x4.rotate_z(Matrix4x4* m, float r)
{
return m.mul(Matrix4x4 {
math::cos(r), -math::sin(r), 0, 0,
math::sin(r), math::cos(r), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
});
}
// r in radians
fn Matrix4x4 Matrix4x4.rotate_y(Matrix4x4* m, float r)
{
return m.mul(Matrix4x4 {
math::cos(r), 0, -math::sin(r), 0,
0, 1, 0, 0,
math::sin(r), 0, math::cos(r), 0,
0, 0, 0, 1,
});
}
// r in radians
fn Matrix4x4 Matrix4x4.rotate_x(Matrix4x4* m, float r)
{
return m.mul(Matrix4x4 {
1, 0, 0, 0,
0, math::cos(r), -math::sin(r), 0,
0, math::sin(r), math::cos(r), 0,
0, 0, 0, 1,
});
}
fn Matrix3x3 Matrix3x3.scale(Matrix3x3* m, float[<2>] v)
{
return m.mul(Matrix3x3 {
v[0], 0, 0,
0, v[1], 0,
0, 0, 1,
});
}
fn Matrix4x4 Matrix4x4.scale(Matrix4x4* m, float[<3>] v)
{
return m.mul(Matrix4x4 {
v[0], 0, 0, 0,
0, v[1], 0, 0,
0, 0, v[2], 0,
0, 0, 0, 1,
});
}
fn Matrix4x4 ortho(float left, float right, float top, float bottom, float near, float far)
{
float width = right - left;
float height = top - bottom;
float depth = far - near;
return Matrix4x4 {
2 / width, 0, 0, 0,
0, 2 / height, 0, 0,
0, 0, -2 / depth, 0,
-(right + left) / width, -(top + bottom) / height, -(far + near) / depth, 1,
};
}
// fov in radians
fn Matrix4x4 perspective(float fov, float aspect_ratio, float near, float far)
{
float top = ((float)math::sin(fov / 2) / (float)math::cos(fov / 2)) * near;
float right = top * aspect_ratio;
float depth = far - near;
return Matrix4x4 {
1 / right, 0, 0, 0,
0, 1 / top, 0, 0,
0, 0, -2 / depth, 0,
0, 0, - (far + near) / depth, 1,
};
}

View File

@@ -0,0 +1,47 @@
module math;
struct SimpleRandom
{
long seed;
}
private const long SIMPLE_RANDOM_MULTIPLIER = 0x5DEECE66D;
private const long SIMPLE_RANDOM_ADDEND = 0xB;
private const long SIMPLE_RANDOM_MASK = (1i64 << 48) - 1;
private fn long simple_random_initial_scramble(long seed)
{
return (seed ^ SIMPLE_RANDOM_MULTIPLIER) & SIMPLE_RANDOM_MASK;
}
private fn int SimpleRandom.next(SimpleRandom* r, int bits)
{
long nextseed = (r.seed * SIMPLE_RANDOM_MULTIPLIER + SIMPLE_RANDOM_ADDEND) & SIMPLE_RANDOM_MASK;
r.seed = nextseed;
return (int)nextseed >> (48 - bits);
}
fn void SimpleRandom.set_seed(SimpleRandom* r, long seed)
{
r.seed = simple_random_initial_scramble(seed);
}
fn int SimpleRandom.next_int(SimpleRandom* r)
{
return r.next(32) @inline;
}
fn bool SimpleRandom.next_bool(SimpleRandom* r)
{
return r.next(1) != 0;
}
fn float SimpleRandom.next_float(SimpleRandom* r)
{
return r.next(24) / (float)(1 << 24);
}
fn double SimpleRandom.next_double(SimpleRandom* r)
{
return (((long)(r.next(26)) << 27) + r.next(27)) * 0x1.0p-53;
}

View File

@@ -0,0 +1,13 @@
module std::math;
fn float __roundevenf(float f) @extname("roundevenf") @weak
{
// Slow implementation
return round(f / 2) * 2;
}
fn double __roundeven(double d) @extname("roundeven") @weak
{
// Slow implementation
return round(d / 2) * 2;
}

View File

@@ -0,0 +1,201 @@
module std::math::easing;
/* Easing equations ported from Robert Penner's equations */
/*
*
* TERMS OF USE - EASING EQUATIONS
*
* Open source under the BSD License.
*
* Copyright © 2001 Robert Penner
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the author nor the names of contributors may be used to endorse
* or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
// Linear Easing functions
fn float linear_none(float t, float b, float c, float d) @inline = c * t / d + b;
fn float linear_in(float t, float b, float c, float d) @inline = c * t / d + b;
fn float linear_out(float t, float b, float c, float d) @inline = c * t / d + b;
fn float linear_inout(float t, float b, float c, float d) @inline = c * t / d + b;
// Sine Easing functions
fn float sine_in(float t, float b, float c, float d) @inline = -c * math::cos(t / d * (float)math::PI_2) + c + b;
fn float sine_out(float t, float b, float c, float d) @inline = c * math::sin(t / d * (float)math::PI_2) + b;
fn float sine_inout(float t, float b, float c, float d) @inline = (-c / 2) * (math::cos((float)math::PI * t / d) - 1) + b;
// Circular Easing functions
fn float circ_in(float t, float b, float c, float d) @inline = -c * (math::sqrt(1 - sq(t / d)) - 1) + b;
fn float circ_out(float t, float b, float c, float d) @inline = c * math::sqrt(1 - sq(t / d - 1)) + b;
fn float circ_inout(float t, float b, float c, float d) @inline
{
t /= d / 2;
return t < 1
? (-c / 2) * (math::sqrt(1 - sq(t)) - 1) + b
: (c / 2) * (math::sqrt(1 - sq(t - 2)) + 1) + b;
}
// Cubic Easing functions
fn float cubic_in(float t, float b, float c, float d) @inline = c * cube(t / d) + b;
fn float cubic_out(float t, float b, float c, float d) @inline = c * (cube(t / d - 1) + 1) + b;
fn float cubic_inout(float t, float b, float c, float d) @inline
{
t /= d / 2;
return t < 1
? (c / 2) * cube(t) + b
: c / 2 * (cube(t - 2) + 2) + b;
}
// Quadratic Easing functions
fn float quad_in(float t, float b, float c, float d) @inline = c * sq(t / d) + b;
fn float quad_out(float t, float b, float c, float d) @inline
{
t /= d;
return -c * t * (t - 2) + b;
}
fn float quad_inout(float t, float b, float c, float d) @inline
{
t /= d / 2;
return t < 1
? (c / 2) * sq(t) + b
: (-c / 2) * ((t - 1) * (t - 3) - 1) + b;
}
// Exponential Easing functions
fn float expo_in(float t, float b, float c, float d) @inline = t ? b : c * math::pow(2.0f, 10 * (t / d - 1)) + b;
fn float expo_out(float t, float b, float c, float d) @inline
{
return (t == d) ? b + c : c * (-math::pow(2.0f, -10 * t / d) + 1) + b;
}
fn float expo_inout(float t, float b, float c, float d) @inline // Ease: Exponential In Out
{
if (t == 0) return b;
if (t == d) return b + c;
t /= d / 2;
return t < 1
? (c / 2) * math::pow(2.0f, 10 * (t - 1)) + b
: (c / 2) * (-math::pow(2.0f, -10 * (t - 1)) + 2) + b;
}
// Back Easing functions
fn float back_in(float t, float b, float c, float d, float s = 1.70158f) @inline
{
t /= d;
return c * sq(t) * ((s + 1) * t - s) + b;
}
fn float back_out(float t, float b, float c, float d, float s = 1.70158f) @inline
{
t = t / d - 1;
return c * (sq(t) * ((s + 1) * t + s) + 1) + b;
}
fn float back_inout(float t, float b, float c, float d, float s = 1.70158f) @inline
{
s *= 1.525f;
t /= d / 2;
if (t < 1)
{
return (c / 2) * sq(t) * ((s + 1) * t - s) + b;
}
t -= 2.0f;
return (c / 2) * (sq(t) * ((s + 1) * t + s) + 2) + b;
}
// Bounce Easing functions
fn float bounce_out(float t, float b, float c, float d) @inline
{
t /= d;
switch
{
case t < 1 / 2.75f:
return c * 7.5625f * sq(t) + b;
case t < 2 / 2.75f:
t -= 1.5f / 2.75f;
return c * (7.5625f * sq(t) + 0.75f) + b;
case t < 2.5f / 2.75f:
t -= 2.25f / 2.75f;
return c * (7.5625f * sq(t) + 0.9375f) + b;
default:
t -= 2.625f / 2.75f;
return c * (7.5625f * sq(t) + 0.984375f) + b;
}
}
fn float bounce_in(float t, float b, float c, float d) @inline = c - bounce_out(d - t, 0, c, d) + b;
fn float bounce_inout(float t, float b, float c, float d) @inline
{
return t < d / 2
? bounce_in(t * 2, 0, c, d) * 0.5f + b
: bounce_out(t * 2 - d, 0, c, d) * 0.5f + b;
}
// Elastic Easing functions
fn float elastic_in(float t, float b, float c, float d) @inline
{
if (t == 0) return b;
t /= d;
if (t == 1) return b + c;
float p = d * 0.3f;
float a = c;
float s = p / 4;
t -= 1;
return -a * math::pow(2.0f, 10 * t) * math::sin((t * d - s) * (2 * (float)math::PI) / p) + b;
}
fn float elastic_out(float t, float b, float c, float d) @inline
{
if (t == 0) return b;
t /= d;
if (t == 1) return b + c;
float p = d * 0.3f;
float a = c;
float s = p / 4;
return a * math::pow(2.0f, -10 * t) * math::sin((t * d - s) * (2 * (float)math::PI) / p) + c + b;
}
fn float elastic_inout(float t, float b, float c, float d) @inline
{
if (t == 0) return b;
t /= d / 2;
if (t == 2) return b + c;
float p = d * (0.3f * 1.5f);
float a = c;
float s = p / 4;
t -= 1;
return t < 0
? -0.5f * a * math::pow(2.0f, 10 * t) * math::sin((t * d - s) * (2 * (float)math::PI)/p) + b
: a * math::pow(2.0f, -10 * t) * math::sin((t * d - s) * (2 * (float)math::PI) / p) * 0.5f + c + b;
}
private macro sq(x) = x * x;
private macro cube(x) = x * x * x;

284
lib/std/math/math_i128.c3 Normal file
View File

@@ -0,0 +1,284 @@
module std::math;
fn int128 __divti3(int128 a, int128 b) @extname("__divti3") @weak
{
int128 sign_a = a >> 127; // -1 : 0
int128 sign_b = b >> 127; // -1 : 0
uint128 unsigned_a = (uint128)(a ^ sign_a) + (-sign_a);
uint128 unsigned_b = (uint128)(b ^ sign_b) + (-sign_b);
sign_a ^= sign_b; // quotient sign
return __udivti3(unsigned_a, unsigned_b) @inline ^ sign_a + (-sign_a);
}
fn uint128 __umodti3(uint128 n, uint128 d) @extname("__umodti3") @weak
{
// Ignore d = 0
uint128 sr = (d ? $$clz(d) : 128) - (n ? $$clz(n) : 128);
// If n < d then sr is wrapping.
// which means we can just return n.
if (sr > 127) return n;
// If d == 1 and n = MAX
if (sr == 127) return 0;
sr++;
uint128 r = n >> sr;
// Follow known algorithm:
n <<= 128 - sr;
for (uint128 carry = 0; sr > 0; sr--)
{
r = (r << 1) | (n >> 127);
n = (n << 1) | carry;
int128 sign = (int128)(d - r - 1) >> 127;
carry = sign & 1;
r -= d & sign;
}
return r;
}
fn uint128 __udivti3(uint128 n, uint128 d) @extname("__udivti3") @weak
{
// Ignore d = 0
uint128 sr = (d ? $$clz(d) : 128) - (n ? $$clz(n) : 128);
// If n < d then sr is wrapping.
// which means we can just return 0.
if (sr > 127) return 0;
// If d == 1 and n = MAX
if (sr == 127) return n;
sr++;
uint128 r = n >> sr;
// Follow known algorithm:
n <<= 128 - sr;
uint128 carry = 0;
for (; sr > 0; sr--)
{
r = (r << 1) | (n >> 127);
n = (n << 1) | carry;
int128 sign = (int128)(d - r - 1) >> 127;
carry = sign & 1;
r -= d & sign;
}
n = (n << 1) | carry;
return n;
}
fn int128 __modti3(int128 a, int128 b) @extname("__modti3") @weak
{
int128 sign = b >> 127;
uint128 unsigned_b = (uint128)(b ^ sign) + (-sign);
sign = a >> 127;
uint128 unsigned_a = (uint128)(a ^ sign) + (-sign);
return __umodti3(unsigned_a, unsigned_b) ^ sign + (-sign);
}
fn float __floattisf(int128 a) @extname("__floattisf") @weak = float_from_i128(float, a);
fn double __floattidf(int128 a) @extname("__floattidf") @weak = float_from_i128(double, a);
fn float __floatuntisf(uint128 a) @extname("__floatuntisf") @weak = float_from_u128(float, a);
fn double __floatuntidf(uint128 a) @extname("__floatuntidf") @weak = float_from_u128(double, a);
fn uint128 __fixunsdfti(double a) @weak @extname("__fixunsdfti") = fixuint(a);
fn uint128 __fixunssfti(float a) @weak @extname("__fixunssfti") = fixuint(a);
fn int128 __fixdfti(double a) @weak @extname("__fixdfti") = fixint(a);
fn int128 __fixsfti(float a) @weak @extname("__fixsfti") = fixint(a);
private macro float_from_i128($Type, a)
{
var $Rep;
$switch ($Type):
$case double:
$Rep = ulong;
const MANT_DIG = DOUBLE_MANT_DIG;
const SIGNIFICANT_BITS = 52;
const EXP_BIAS = 1023;
const MANTISSA_MASK = 0xFFFFF_FFFF_FFFFu64;
const SIGN_BIT = 1u64 << 63;
$case float:
$Rep = uint;
const MANT_DIG = FLOAT_MANT_DIG;
const EXP_BIAS = 127;
const SIGNIFICANT_BITS = 23;
const MANTISSA_MASK = 0x7F_FFFFu32;
const SIGN_BIT = 1u32 << 31;
$case float16:
$Rep = ushort;
const MANT_DIG = HALF_MANT_DIG;
$case float128:
$Rep = uint128;
const MANT_DIG = QUAD_MANT_DIG;
$endswitch;
if (a == 0) return ($Type)0;
// Grab and remove sign.
int128 sign = a >> 127;
a = (a ^ sign) - sign;
int sd = 128 - (int)$$clz(a); // digits
int e = sd - 1; // exponent
if (sd > MANT_DIG)
{
switch (sd)
{
case MANT_DIG + 1:
a <<= 1;
case MANT_DIG + 2:
break;
default:
a = (a >> (sd - (MANT_DIG + 2)))
| (uint128)((a & ((uint128)(-1) >> ((128 + MANT_DIG + 2) - sd))) != 0);
}
a |= (uint128)((a & 4) != 0);
a++;
a >>= 2;
if (a & (1i128 << MANT_DIG))
{
a >>= 1;
e++;
}
}
else
{
a <<= (MANT_DIG - sd);
}
return bitcast(((($Rep)sign & SIGN_BIT) | ((($Rep)e + ($Rep)EXP_BIAS) << SIGNIFICANT_BITS)) | (($Rep)a & ($Rep)MANTISSA_MASK), $Type);
}
private macro float_from_u128($Type, a)
{
var $Rep;
$switch ($Type):
$case double:
$Rep = ulong;
const MANT_DIG = DOUBLE_MANT_DIG;
const SIGNIFICANT_BITS = 52;
const EXP_BIAS = 1023;
const MANTISSA_MASK = 0xFFFFF_FFFF_FFFFu64;
$case float:
$Rep = uint;
const MANT_DIG = FLOAT_MANT_DIG;
const EXP_BIAS = 127;
const SIGNIFICANT_BITS = 23;
const MANTISSA_MASK = 0x7F_FFFFu32;
$case float16:
$Rep = ushort;
const MANT_DIG = HALF_MANT_DIG;
$case float128:
$Rep = uint128;
const MANT_DIG = QUAD_MANT_DIG;
$endswitch;
if (a == 0) return ($Type)0;
int sd = 128 - (int)$$clz(a); // digits
int e = sd - 1; // exponent
if (sd > MANT_DIG)
{
switch (sd)
{
case MANT_DIG + 1:
a <<= 1;
case MANT_DIG + 2:
break;
default:
a = (a >> (sd - (MANT_DIG + 2)))
| (uint128)((a & ((uint128)(-1) >> ((128 + MANT_DIG + 2) - sd))) != 0);
}
a |= (uint128)((a & 4) != 0);
a++;
a >>= 2;
if (a & (1i128 << MANT_DIG))
{
a >>= 1;
e++;
}
}
else
{
a <<= (MANT_DIG - sd);
}
return bitcast(((($Rep)e + ($Rep)EXP_BIAS) << SIGNIFICANT_BITS) | (($Rep)a & ($Rep)MANTISSA_MASK), $Type);
}
private macro fixuint(a)
{
var $Rep;
$switch ($typeof(a)):
$case double:
$Rep = ulong;
const EXPONENT_BITS = 11;
const SIGNIFICANT_BITS = 52;
$case float:
$Rep = uint;
const EXPONENT_BITS = 8;
const SIGNIFICANT_BITS = 23;
$case float16:
$Rep = ushort;
const EXPONENT_BITS = 5;
const SIGNIFICANT_BITS = 10;
$case float128:
$Rep = uint128;
const EXPONENT_BITS = 15;
const SIGNIFICANT_BITS = 112;
$endswitch;
const $Rep MAX_EXPONENT = ($Rep)1 << EXPONENT_BITS - 1u;
const $Rep EXPONENT_BIAS = MAX_EXPONENT >> 1u;
const $Rep ONE_REP =EXPONENT_BIAS << SIGNIFICANT_BITS;
const $Rep SIGN_BIT = ($Rep)1 << (EXPONENT_BITS + SIGNIFICANT_BITS);
const $Rep ABS_MASK = SIGN_BIT - 1u;
const $Rep IMPLICIT_BIT = ($Rep)1 << SIGNIFICANT_BITS;
const $Rep SIGNIFICANT_MASK = IMPLICIT_BIT - 1u;
const $Rep EXPONENT_MASK = ABS_MASK ^ SIGNIFICANT_MASK;
const $Rep QUIET_BIT = IMPLICIT_BIT >> 1;
const $Rep QNAN_REP = EXPONENT_MASK | QUIET_BIT;
const $Rep INF_REP = EXPONENT_MASK;
$Rep rep = bitcast(a, $Rep);
$Rep abs = rep & ABS_MASK;
int sign = rep & SIGN_BIT ? -1 : 1;
int exponent = (int)((abs >> SIGNIFICANT_BITS) - EXPONENT_BIAS);
$Rep significand = (abs & SIGNIFICANT_MASK) | IMPLICIT_BIT;
if (sign == -1 || exponent < 0) return 0u128;
if ((uint)exponent >= uint128.sizeof * 8) return ~0u128;
if (exponent < SIGNIFICANT_BITS) return (uint128)significand >> (SIGNIFICANT_BITS - exponent);
return (uint128)significand << (exponent - SIGNIFICANT_BITS);
}
private macro fixint(a)
{
var $Rep;
$switch ($typeof(a)):
$case double:
$Rep = ulong;
const EXPONENT_BITS = 11;
const SIGNIFICANT_BITS = 52;
$case float:
$Rep = uint;
const EXPONENT_BITS = 8;
const SIGNIFICANT_BITS = 23;
$case float16:
$Rep = ushort;
const EXPONENT_BITS = 5;
const SIGNIFICANT_BITS = 10;
$case float128:
$Rep = uint128;
const EXPONENT_BITS = 15;
const SIGNIFICANT_BITS = 112;
$endswitch;
const $Rep MAX_EXPONENT = ($Rep)1 << EXPONENT_BITS - 1u;
const $Rep EXPONENT_BIAS = MAX_EXPONENT >> 1u;
const $Rep ONE_REP = EXPONENT_BIAS << SIGNIFICANT_BITS;
const $Rep SIGN_BIT = ($Rep)1 << (EXPONENT_BITS + SIGNIFICANT_BITS);
const $Rep ABS_MASK = SIGN_BIT - 1u;
const $Rep IMPLICIT_BIT = ($Rep)1 << SIGNIFICANT_BITS;
const $Rep SIGNIFICANT_MASK = IMPLICIT_BIT - 1u;
const $Rep EXPONENT_MASK = ABS_MASK ^ SIGNIFICANT_MASK;
const $Rep QUIET_BIT = IMPLICIT_BIT >> 1;
const $Rep QNAN_REP = EXPONENT_MASK | QUIET_BIT;
const $Rep INF_REP = EXPONENT_MASK;
$Rep rep = bitcast(a, $Rep);
$Rep abs = rep & ABS_MASK;
int sign = rep & SIGN_BIT ? -1 : 1;
int exponent = (int)((abs >> SIGNIFICANT_BITS) - EXPONENT_BIAS);
$Rep significand = (abs & SIGNIFICANT_MASK) | IMPLICIT_BIT;
if (exponent < 0) return 0;
if ((uint)exponent >= uint128.sizeof * 8) return sign == 1 ? int128.max : int128.min;
if (exponent < SIGNIFICANT_BITS) return sign * ((int128)significand >> (SIGNIFICANT_BITS - exponent));
return sign * ((int128)significand << (exponent - SIGNIFICANT_BITS));
}