fixed.odin 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. package math_fixed
  2. import "core:math"
  3. import "core:strconv"
  4. import "intrinsics"
  5. _ :: intrinsics;
  6. Fixed :: struct($Backing: typeid, Fraction_Width: uint)
  7. where
  8. intrinsics.type_is_integer(Backing),
  9. 0 <= Fraction_Width,
  10. Fraction_Width <= 8*size_of(Backing) {
  11. i: Backing,
  12. }
  13. Fixed4_4 :: distinct Fixed(i8, 4);
  14. Fixed5_3 :: distinct Fixed(i8, 3);
  15. Fixed6_2 :: distinct Fixed(i8, 2);
  16. Fixed7_1 :: distinct Fixed(i8, 1);
  17. Fixed8_8 :: distinct Fixed(i16, 8);
  18. Fixed13_3 :: distinct Fixed(i16, 3);
  19. Fixed16_16 :: distinct Fixed(i32, 16);
  20. Fixed26_6 :: distinct Fixed(i32, 6);
  21. Fixed32_32 :: distinct Fixed(i64, 32);
  22. Fixed52_12 :: distinct Fixed(i64, 12);
  23. init_from_f64 :: proc(x: ^$T/Fixed($Backing, $Fraction_Width), val: f64) {
  24. i, f := math.modf(val);
  25. x.i = Backing(f * (1<<Fraction_Width));
  26. x.i &= 1<<Fraction_Width - 1;
  27. x.i |= Backing(i) << Fraction_Width;
  28. }
  29. init_from_parts :: proc(x: ^$T/Fixed($Backing, $Fraction_Width), integer, fraction: Backing) {
  30. i, f := math.modf(val);
  31. x.i = fraction;
  32. x.i &= 1<<Fraction_Width - 1;
  33. x.i |= integer;
  34. }
  35. to_f64 :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> f64 {
  36. res := f64(x.i >> Fraction_Width);
  37. res += f64(x.i & (1<<Fraction_Width-1)) / f64(1<<Fraction_Width);
  38. return res;
  39. }
  40. add :: proc(x, y: $T/Fixed) -> T {
  41. return {x.i + y.i};
  42. }
  43. sub :: proc(x, y: $T/Fixed) -> T {
  44. return {x.i - y.i};
  45. }
  46. mul :: proc(x, y: $T/Fixed($Backing, $Fraction_Width)) -> (z: T) {
  47. z.i = intrinsics.fixed_point_mul(x.i, y.i, Fraction_Width);
  48. return;
  49. }
  50. mul_sat :: proc(x, y: $T/Fixed($Backing, $Fraction_Width)) -> (z: T) {
  51. z.i = intrinsics.fixed_point_mul_sat(x.i, y.i, Fraction_Width);
  52. return;
  53. }
  54. div :: proc(x, y: $T/Fixed($Backing, $Fraction_Width)) -> (z: T) {
  55. z.i = intrinsics.fixed_point_div(x.i, y.i, Fraction_Width);
  56. return;
  57. }
  58. div_sat :: proc(x, y: $T/Fixed($Backing, $Fraction_Width)) -> (z: T) {
  59. z.i = intrinsics.fixed_point_div_sat(x.i, y.i, Fraction_Width);
  60. return;
  61. }
  62. floor :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing {
  63. return x.i >> Fraction_Width;
  64. }
  65. ceil :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing {
  66. Integer :: 8*size_of(Backing) - Fraction_Width;
  67. return (x.i + (1 << Integer-1)) >> Fraction_Width;
  68. }
  69. round :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing {
  70. Integer :: 8*size_of(Backing) - Fraction_Width;
  71. return (x.i + (1 << (Integer - 1))) >> Fraction_Width;
  72. }
  73. append :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string {
  74. x := x;
  75. buf: [48]byte;
  76. i := 0;
  77. if x.i < 0 {
  78. buf[i] = '-';
  79. i += 1;
  80. x.i = -x.i;
  81. }
  82. integer := x.i >> Fraction_Width;
  83. fraction := x.i & (1<<Fraction_Width - 1);
  84. s := strconv.append_uint(buf[i:], u64(integer), 10);
  85. i += len(s);
  86. if fraction != 0 {
  87. buf[i] = '.';
  88. i += 1;
  89. for fraction > 0 {
  90. fraction *= 10;
  91. buf[i] = byte('0' + (fraction>>Fraction_Width));
  92. i += 1;
  93. fraction &= 1<<Fraction_Width - 1;
  94. }
  95. }
  96. n := copy(dst, buf[:i]);
  97. return string(dst[:i]);
  98. }
  99. to_string :: proc(x: $T/Fixed($Backing, $Fraction_Width), allocator := context.allocator) -> string {
  100. buf: [48]byte;
  101. s := append(buf[:], x);
  102. str := make([]byte, len(s), allocator);
  103. copy(str, s);
  104. return string(str);
  105. }