1 #pragma once
2
3 /** @file fixed.h Fixed-point 48.16 math routines.
4
5 @authors Copyright (c) 2020 Jaakko Keränen <jaakko.keranen@iki.fi>
6
7 @par License
8
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions are met:
11
12 1. Redistributions of source code must retain the above copyright notice, this
13 list of conditions and the following disclaimer.
14 2. Redistributions in binary form must reproduce the above copyright notice,
15 this list of conditions and the following disclaimer in the documentation
16 and/or other materials provided with the distribution.
17
18 <small>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
22 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</small>
28 */
29
30 #include "defs.h"
31 #include "random.h"
32
33 #include <math.h>
34
35 iDeclareType(Fixed)
36
37 typedef int64_t iFixed64;
38 #if defined(__SIZEOF_INT128__)
39 typedef __int128_t iFixedLong;
40 #else
41 typedef int64_t iFixedLong; /* oops, will overflow */
42 #endif
43
44 struct Impl_Fixed {
45 union {
46 iFixed64 v;
47 struct {
48 uint64_t frac : 16;
49 uint64_t wnum : 47;
50 uint64_t sign : 1;
51 } comp;
52 };
53 };
54
55 #define iFixedFracBits 16
56 #define iFixedUnit (1 << iFixedFracBits)
57 #define iFixedMaxWNum ((((iFixed64) 1) << 47) - 1)
58
zero_Fixed(void)59 iLocalDef iFixed zero_Fixed(void) {
60 return (iFixed){ .v = 0 };
61 }
62
one_Fixed(void)63 iLocalDef iFixed one_Fixed(void) {
64 return (iFixed){ .v = iFixedUnit };
65 }
66
half_Fixed(void)67 iLocalDef iFixed half_Fixed(void) {
68 return (iFixed){ .v = iFixedUnit >> 1 };
69 }
70
init_Fixed(iFixed64 fp)71 iLocalDef iFixed init_Fixed(iFixed64 fp) {
72 return (iFixed){ .v = fp };
73 }
74
initi_Fixed(int32_t i)75 iLocalDef iFixed initi_Fixed(int32_t i) {
76 return (iFixed){ .v = i << iFixedFracBits };
77 }
78
initf_Fixed(float f)79 iLocalDef iFixed initf_Fixed(float f) {
80 return (iFixed){ .v = (iFixed64) (f * iFixedUnit) };
81 }
82
initd_Fixed(double d)83 iLocalDef iFixed initd_Fixed(double d) {
84 return (iFixed){ .v = (iFixed64) (d * iFixedUnit) };
85 }
86
add_Fixed(const iFixed a,const iFixed b)87 iLocalDef iFixed add_Fixed(const iFixed a, const iFixed b) {
88 return (iFixed){ .v = a.v + b.v };
89 }
90
addv_Fixed(iFixed * a,const iFixed b)91 iLocalDef void addv_Fixed(iFixed *a, const iFixed b) {
92 a->v += b.v;
93 }
94
sub_Fixed(const iFixed a,const iFixed b)95 iLocalDef iFixed sub_Fixed(const iFixed a, const iFixed b) {
96 return (iFixed){ .v = a.v - b.v };
97 }
98
subv_Fixed(iFixed * a,const iFixed b)99 iLocalDef void subv_Fixed(iFixed *a, const iFixed b) {
100 a->v -= b.v;
101 }
102
mul_Fixed(const iFixed a,const iFixed b)103 iLocalDef iFixed mul_Fixed(const iFixed a, const iFixed b) {
104 return init_Fixed((((iFixedLong) a.v * (iFixedLong) b.v) >> iFixedFracBits));
105 }
106
mulv_Fixed(iFixed * a,const iFixed b)107 iLocalDef void mulv_Fixed(iFixed *a, const iFixed b) {
108 *a = mul_Fixed(*a, b);
109 }
110
muli_Fixed(const iFixed a,int i)111 iLocalDef iFixed muli_Fixed(const iFixed a, int i) {
112 return init_Fixed(a.v * i);
113 }
114
mulf_Fixed(const iFixed a,float f)115 iLocalDef iFixed mulf_Fixed(const iFixed a, float f) {
116 return init_Fixed((iFixed64) (a.v * f));
117 }
118
div_Fixed(const iFixed a,const iFixed b)119 iLocalDef iFixed div_Fixed(const iFixed a, const iFixed b) {
120 return init_Fixed(((iFixedLong) a.v << iFixedFracBits) / (iFixedLong) b.v);
121 }
122
divv_Fixed(iFixed * a,const iFixed b)123 iLocalDef void divv_Fixed(iFixed *a, const iFixed b) {
124 *a = div_Fixed(*a, b);
125 }
126
divi_Fixed(const iFixed a,int i)127 iLocalDef iFixed divi_Fixed(const iFixed a, int i) {
128 return div_Fixed(a, initi_Fixed(i));
129 }
130
divf_Fixed(const iFixed a,float f)131 iLocalDef iFixed divf_Fixed(const iFixed a, float f) {
132 return div_Fixed(a, initf_Fixed(f));
133 }
134
value_Fixed(const iFixed a)135 iLocalDef iFixed64 value_Fixed(const iFixed a) {
136 return a.v;
137 }
138
i64_Fixed(const iFixed a)139 iLocalDef int64_t i64_Fixed(const iFixed a) {
140 return a.v >> iFixedFracBits;
141 }
142
i32_Fixed(const iFixed a)143 iLocalDef int32_t i32_Fixed(const iFixed a) {
144 return (int32_t) a.v >> iFixedFracBits;
145 }
146
f64_Fixed(const iFixed a)147 iLocalDef double f64_Fixed(const iFixed a) {
148 return (double) a.v / iFixedUnit;
149 }
150
f32_Fixed(const iFixed a)151 iLocalDef float f32_Fixed(const iFixed a) {
152 return (float) f64_Fixed(a);
153 }
154
min_Fixed(const iFixed a,const iFixed b)155 iLocalDef iFixed min_Fixed(const iFixed a, const iFixed b) { return init_Fixed(iMin(a.v, b.v)); }
max_Fixed(const iFixed a,const iFixed b)156 iLocalDef iFixed max_Fixed(const iFixed a, const iFixed b) { return init_Fixed(iMax(a.v, b.v)); }
neg_Fixed(const iFixed a)157 iLocalDef iFixed neg_Fixed(const iFixed a) { return init_Fixed(-a.v); }
abs_Fixed(const iFixed a)158 iLocalDef iFixed abs_Fixed(const iFixed a) { if (a.comp.sign) return neg_Fixed(a); else return a; }
159
mix_Fixed(const iFixed a,const iFixed b,const iFixed t)160 iLocalDef iFixed mix_Fixed(const iFixed a, const iFixed b, const iFixed t) {
161 return add_Fixed(a, mul_Fixed(sub_Fixed(b, a), t));
162 }
163
random_Fixed(void)164 iLocalDef iFixed random_Fixed(void) {
165 return initf_Fixed(iRandomf());
166 }
167