aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2021-04-01 17:09:34 +0100
committergingerBill <bill@gingerbill.org>2021-04-01 17:09:34 +0100
commitbcda9ddee75510b5b79d212dd123bcd5e6136f0f (patch)
tree9ec2b58eb5c22a90972252055270d5a6ac4d1661 /core
parent4a66cbb1f40ce084b2e1e73bbce559049771fb1a (diff)
Add core:math/fixed
Diffstat (limited to 'core')
-rw-r--r--core/math/fixed/fixed.odin133
1 files changed, 133 insertions, 0 deletions
diff --git a/core/math/fixed/fixed.odin b/core/math/fixed/fixed.odin
new file mode 100644
index 000000000..115df177a
--- /dev/null
+++ b/core/math/fixed/fixed.odin
@@ -0,0 +1,133 @@
+package math_fixed
+
+import "core:math"
+import "core:strconv"
+
+import "intrinsics"
+_ :: intrinsics;
+
+Fixed :: struct($Backing: typeid, Fraction_Width: uint)
+ where
+ intrinsics.type_is_integer(Backing),
+ 0 <= Fraction_Width,
+ Fraction_Width <= 8*size_of(Backing) {
+ i: Backing,
+}
+
+Fixed4_4 :: distinct Fixed(i8, 4);
+Fixed5_3 :: distinct Fixed(i8, 3);
+Fixed6_2 :: distinct Fixed(i8, 2);
+Fixed7_1 :: distinct Fixed(i8, 1);
+
+Fixed8_8 :: distinct Fixed(i16, 8);
+Fixed13_3 :: distinct Fixed(i16, 3);
+
+Fixed16_16 :: distinct Fixed(i32, 16);
+Fixed26_6 :: distinct Fixed(i32, 6);
+
+Fixed32_32 :: distinct Fixed(i64, 32);
+Fixed52_12 :: distinct Fixed(i64, 12);
+
+
+init_from_f64 :: proc(x: ^$T/Fixed($Backing, $Fraction_Width), val: f64) {
+ i, f := math.modf(val);
+ x.i = Backing(f * (1<<Fraction_Width));
+ x.i &= 1<<Fraction_Width - 1;
+ x.i |= Backing(i) << Fraction_Width;
+}
+
+
+init_from_parts :: proc(x: ^$T/Fixed($Backing, $Fraction_Width), integer, fraction: Backing) {
+ i, f := math.modf(val);
+ x.i = fraction;
+ x.i &= 1<<Fraction_Width - 1;
+ x.i |= integer;
+}
+
+to_f64 :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> f64 {
+ res := f64(x.i >> Fraction_Width);
+ res += f64(x.i & (1<<Fraction_Width-1)) / f64(1<<Fraction_Width);
+ return res;
+}
+
+
+add :: proc(x, y: $T/Fixed) -> T {
+ return {x.i + y.i};
+}
+sub :: proc(x, y: $T/Fixed) -> T {
+ return {x.i - y.i};
+}
+
+mul :: proc(x, y: $T/Fixed($Backing, $Fraction_Width)) -> (z: T) {
+ z.i = intrinsics.fixed_point_mul(x.i, y.i, Fraction_Width);
+ return;
+}
+mul_sat :: proc(x, y: $T/Fixed($Backing, $Fraction_Width)) -> (z: T) {
+ z.i = intrinsics.fixed_point_mul_sat(x.i, y.i, Fraction_Width);
+ return;
+}
+
+div :: proc(x, y: $T/Fixed($Backing, $Fraction_Width)) -> (z: T) {
+ z.i = intrinsics.fixed_point_div(x.i, y.i, Fraction_Width);
+ return;
+}
+div_sat :: proc(x, y: $T/Fixed($Backing, $Fraction_Width)) -> (z: T) {
+ z.i = intrinsics.fixed_point_div_sat(x.i, y.i, Fraction_Width);
+ return;
+}
+
+
+floor :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing {
+ return x.i >> Fraction_Width;
+}
+ceil :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing {
+ Integer :: 8*size_of(Backing) - Fraction_Width;
+ return (x.i + (1 << Integer-1)) >> Fraction_Width;
+}
+round :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing {
+ Integer :: 8*size_of(Backing) - Fraction_Width;
+ return (x.i + (1 << (Integer - 1))) >> Fraction_Width;
+}
+
+
+
+append :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string {
+ x := x;
+ buf: [48]byte;
+ i := 0;
+ if x.i < 0 {
+ buf[i] = '-';
+ i += 1;
+ x.i = -x.i;
+ }
+
+ integer := x.i >> Fraction_Width;
+ fraction := x.i & (1<<Fraction_Width - 1);
+
+ s := strconv.append_uint(buf[i:], u64(integer), 10);
+ i += len(s);
+ if fraction != 0 {
+ buf[i] = '.';
+ i += 1;
+ for fraction > 0 {
+ fraction *= 10;
+ buf[i] = byte('0' + (fraction>>Fraction_Width));
+ i += 1;
+ fraction &= 1<<Fraction_Width - 1;
+ }
+ }
+
+
+
+ n := copy(dst, buf[:i]);
+ return string(dst[:i]);
+}
+
+
+to_string :: proc(x: $T/Fixed($Backing, $Fraction_Width), allocator := context.allocator) -> string {
+ buf: [48]byte;
+ s := append(buf[:], x);
+ str := make([]byte, len(s), allocator);
+ copy(str, s);
+ return string(str);
+}