1 | /* |
2 | * Fixed point type. |
3 | * Based on Allegro library by Shawn Hargreaves. |
4 | */ |
5 | |
6 | #ifndef FIXMATH_FIXMATH_H |
7 | #define FIXMATH_FIXMATH_H |
8 | |
9 | #include "base/ints.h" |
10 | #include <cerrno> |
11 | |
12 | namespace fixmath { |
13 | |
14 | typedef int32_t fixed; |
15 | |
16 | extern const fixed fixtorad_r; |
17 | extern const fixed radtofix_r; |
18 | |
19 | extern fixed _cos_tbl[]; |
20 | extern fixed _tan_tbl[]; |
21 | extern fixed _acos_tbl[]; |
22 | |
23 | fixed fixsqrt(fixed x); |
24 | fixed fixhypot(fixed x, fixed y); |
25 | fixed fixatan(fixed x); |
26 | fixed fixatan2(fixed y, fixed x); |
27 | |
28 | // ftofix and fixtof are used in generic C versions of fixmul and fixdiv |
29 | inline fixed ftofix(double x) { |
30 | if (x > 32767.0) { |
31 | errno = ERANGE; |
32 | return 0x7FFFFFFF; |
33 | } |
34 | |
35 | if (x < -32767.0) { |
36 | errno = ERANGE; |
37 | return -0x7FFFFFFF; |
38 | } |
39 | |
40 | return (fixed)(x * 65536.0 + (x < 0 ? -0.5 : 0.5)); |
41 | } |
42 | |
43 | inline double fixtof(fixed x) { |
44 | return (double)x / 65536.0; |
45 | }; |
46 | |
47 | inline fixed fixadd(fixed x, fixed y) { |
48 | fixed result = x + y; |
49 | |
50 | if (result >= 0) { |
51 | if ((x < 0) && (y < 0)) { |
52 | errno = ERANGE; |
53 | return -0x7FFFFFFF; |
54 | } |
55 | else |
56 | return result; |
57 | } |
58 | else { |
59 | if ((x > 0) && (y > 0)) { |
60 | errno = ERANGE; |
61 | return 0x7FFFFFFF; |
62 | } |
63 | else |
64 | return result; |
65 | } |
66 | } |
67 | |
68 | inline fixed fixsub(fixed x, fixed y) { |
69 | fixed result = x - y; |
70 | |
71 | if (result >= 0) { |
72 | if ((x < 0) && (y > 0)) { |
73 | errno = ERANGE; |
74 | return -0x7FFFFFFF; |
75 | } |
76 | else |
77 | return result; |
78 | } |
79 | else { |
80 | if ((x > 0) && (y < 0)) { |
81 | errno = ERANGE; |
82 | return 0x7FFFFFFF; |
83 | } |
84 | else |
85 | return result; |
86 | } |
87 | } |
88 | |
89 | inline fixed fixmul(fixed x, fixed y) { |
90 | return ftofix(fixtof(x) * fixtof(y)); |
91 | } |
92 | |
93 | inline fixed fixdiv(fixed x, fixed y) { |
94 | if (y == 0) { |
95 | errno = ERANGE; |
96 | return (x < 0) ? -0x7FFFFFFF : 0x7FFFFFFF; |
97 | } |
98 | else |
99 | return ftofix(fixtof(x) / fixtof(y)); |
100 | } |
101 | |
102 | inline int fixfloor(fixed x) { |
103 | /* (x >> 16) is not portable */ |
104 | if (x >= 0) |
105 | return (x >> 16); |
106 | else |
107 | return ~((~x) >> 16); |
108 | } |
109 | |
110 | inline int fixceil(fixed x) { |
111 | if (x > 0x7FFF0000) { |
112 | errno = ERANGE; |
113 | return 0x7FFF; |
114 | } |
115 | |
116 | return fixfloor(x + 0xFFFF); |
117 | } |
118 | |
119 | inline fixed itofix(int x) { |
120 | return x << 16; |
121 | } |
122 | |
123 | inline int fixtoi(fixed x) { |
124 | return fixfloor(x) + ((x & 0x8000) >> 15); |
125 | } |
126 | |
127 | inline fixed fixcos(fixed x) { |
128 | return _cos_tbl[((x + 0x4000) >> 15) & 0x1FF]; |
129 | } |
130 | |
131 | inline fixed fixsin(fixed x) { |
132 | return _cos_tbl[((x - 0x400000 + 0x4000) >> 15) & 0x1FF]; |
133 | } |
134 | |
135 | inline fixed fixtan(fixed x) { |
136 | return _tan_tbl[((x + 0x4000) >> 15) & 0xFF]; |
137 | } |
138 | |
139 | inline fixed fixacos(fixed x) { |
140 | if ((x < -65536) || (x > 65536)) { |
141 | errno = EDOM; |
142 | return 0; |
143 | } |
144 | |
145 | return _acos_tbl[(x+65536+127)>>8]; |
146 | } |
147 | |
148 | inline fixed fixasin(fixed x) { |
149 | if ((x < -65536) || (x > 65536)) { |
150 | errno = EDOM; |
151 | return 0; |
152 | } |
153 | |
154 | return 0x00400000 - _acos_tbl[(x+65536+127)>>8]; |
155 | } |
156 | |
157 | } // namespace fixmath |
158 | |
159 | #endif |
160 | |