Line | Branch | Exec | Source |
---|---|---|---|
1 | /* GATE PROJECT LICENSE: | ||
2 | +----------------------------------------------------------------------------+ | ||
3 | | Copyright(c) 2018-2025, Stefan Meislinger <sm@opengate.at> | | ||
4 | | All rights reserved. | | ||
5 | | | | ||
6 | | Redistribution and use in source and binary forms, with or without | | ||
7 | | modification, are permitted provided that the following conditions are met:| | ||
8 | | | | ||
9 | | 1. Redistributions of source code must retain the above copyright notice, | | ||
10 | | this list of conditions and the following disclaimer. | | ||
11 | | 2. Redistributions in binary form must reproduce the above copyright | | ||
12 | | notice, this list of conditions and the following disclaimer in the | | ||
13 | | documentation and/or other materials provided with the distribution. | | ||
14 | | | | ||
15 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"| | ||
16 | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | ||
17 | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ||
18 | | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | | ||
19 | | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | ||
20 | | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | ||
21 | | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | ||
22 | | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | ||
23 | | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | ||
24 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | | ||
25 | | THE POSSIBILITY OF SUCH DAMAGE. | | ||
26 | +----------------------------------------------------------------------------+ | ||
27 | */ | ||
28 | |||
29 | #include "gate/mathematics.h" | ||
30 | |||
31 | #if defined(GATE_SYS_EFI) | ||
32 | //# define GATE_CORE_MATH_EFI_IMPL 1 | ||
33 | # define GATE_CORE_MATH_STD_IMPL 1 | ||
34 | #else | ||
35 | # define GATE_CORE_MATH_STD_IMPL 1 | ||
36 | #endif | ||
37 | |||
38 | /***************************** | ||
39 | * Generic implementations * | ||
40 | *****************************/ | ||
41 | |||
42 | #include <stdarg.h> | ||
43 | #include <float.h> | ||
44 | |||
45 | ✗ | void gate_decimal_init(gate_decimal_t* deci, gate_int32_t int_num, gate_uint32_t micro_num) | |
46 | { | ||
47 | ✗ | deci->value = (gate_decimal_primitive_t)(int_num * GATE_DECIMAL_FACTOR); | |
48 | ✗ | deci->value += (gate_decimal_primitive_t)(micro_num % GATE_DECIMAL_FACTOR); | |
49 | ✗ | } | |
50 | ✗ | gate_int32_t gate_decimal_get_int(gate_decimal_t const* deci) | |
51 | { | ||
52 | ✗ | return (gate_int32_t)(deci->value / GATE_DECIMAL_FACTOR); | |
53 | } | ||
54 | ✗ | gate_uint32_t gate_decimal_get_micro(gate_decimal_t const* deci) | |
55 | { | ||
56 | ✗ | if (deci->value < 0) | |
57 | { | ||
58 | ✗ | return (gate_uint32_t)((-deci->value) % GATE_DECIMAL_FACTOR); | |
59 | } | ||
60 | else | ||
61 | { | ||
62 | ✗ | return (gate_uint32_t)(deci->value % GATE_DECIMAL_FACTOR); | |
63 | } | ||
64 | } | ||
65 | ✗ | gate_real32_t gate_decimal_get_float(gate_decimal_t const* micro) | |
66 | { | ||
67 | ✗ | return (gate_real32_t)micro->value / (gate_real32_t)GATE_DECIMAL_FACTOR; | |
68 | } | ||
69 | |||
70 | ✗ | int gate_decimal_compare(gate_decimal_t const* a, gate_decimal_t const* b) | |
71 | { | ||
72 | ✗ | if (a->value < b->value) | |
73 | { | ||
74 | ✗ | return -1; | |
75 | } | ||
76 | ✗ | else if (a->value > b->value) | |
77 | { | ||
78 | ✗ | return 1; | |
79 | } | ||
80 | ✗ | return 0; | |
81 | } | ||
82 | |||
83 | |||
84 | ✗ | void gate_decimal_add_int(gate_decimal_t* deci, gate_int32_t value) | |
85 | { | ||
86 | ✗ | deci->value += (gate_decimal_primitive_t)value * GATE_DECIMAL_FACTOR; | |
87 | ✗ | } | |
88 | ✗ | void gate_decimal_sub_int(gate_decimal_t* deci, gate_int32_t value) | |
89 | { | ||
90 | ✗ | deci->value -= (gate_decimal_primitive_t)value * GATE_DECIMAL_FACTOR; | |
91 | ✗ | } | |
92 | ✗ | void gate_decimal_mul_int(gate_decimal_t* deci, gate_int32_t value) | |
93 | { | ||
94 | ✗ | deci->value *= (gate_decimal_primitive_t)value; | |
95 | ✗ | } | |
96 | ✗ | void gate_decimal_div_int(gate_decimal_t* deci, gate_int32_t value) | |
97 | { | ||
98 | ✗ | deci->value /= (gate_decimal_primitive_t)value; | |
99 | ✗ | } | |
100 | |||
101 | ✗ | void gate_decimal_add_dec(gate_decimal_t* deci, gate_decimal_t const* ptr_value) | |
102 | { | ||
103 | ✗ | deci->value += ptr_value->value; | |
104 | ✗ | } | |
105 | ✗ | void gate_decimal_sub_dec(gate_decimal_t* deci, gate_decimal_t const* ptr_value) | |
106 | { | ||
107 | ✗ | deci->value -= ptr_value->value; | |
108 | ✗ | } | |
109 | ✗ | void gate_decimal_mul_dec(gate_decimal_t* deci, gate_decimal_t const* ptr_value) | |
110 | { | ||
111 | ✗ | deci->value *= ptr_value->value; | |
112 | ✗ | deci->value /= (gate_decimal_primitive_t)GATE_DECIMAL_FACTOR; | |
113 | ✗ | } | |
114 | ✗ | void gate_decimal_div_dec(gate_decimal_t* deci, gate_decimal_t const* ptr_value) | |
115 | { | ||
116 | ✗ | gate_int64_t r = deci->value % ptr_value->value; | |
117 | ✗ | deci->value /= ptr_value->value; | |
118 | ✗ | deci->value *= (gate_decimal_primitive_t)GATE_DECIMAL_FACTOR; | |
119 | ✗ | deci->value += (gate_decimal_primitive_t)(r * GATE_DECIMAL_FACTOR / ptr_value->value); | |
120 | ✗ | } | |
121 | |||
122 | ✗ | void gate_decimal_add_flt(gate_decimal_t* deci, gate_real32_t value) | |
123 | { | ||
124 | ✗ | deci->value += (gate_decimal_primitive_t)(value * (gate_real32_t)GATE_DECIMAL_FACTOR); | |
125 | ✗ | } | |
126 | ✗ | void gate_decimal_sub_flt(gate_decimal_t* deci, gate_real32_t value) | |
127 | { | ||
128 | ✗ | deci->value -= (gate_decimal_primitive_t)(value * (gate_real32_t)GATE_DECIMAL_FACTOR); | |
129 | ✗ | } | |
130 | ✗ | void gate_decimal_mul_flt(gate_decimal_t* deci, gate_real32_t value) | |
131 | { | ||
132 | ✗ | deci->value = (gate_decimal_primitive_t)((gate_real32_t)deci->value * value); | |
133 | ✗ | } | |
134 | ✗ | void gate_decimal_div_flt(gate_decimal_t* deci, gate_real32_t value) | |
135 | { | ||
136 | ✗ | deci->value = (gate_decimal_primitive_t)((gate_real32_t)deci->value / value); | |
137 | ✗ | } | |
138 | ✗ | void gate_decimal_sqrt(gate_decimal_t* deci) | |
139 | { | ||
140 | static gate_decimal_t n2 = GATE_DECIMAL_INIT(2, 0); | ||
141 | ✗ | gate_decimal_t a = GATE_DECIMAL_INIT(1255, 0); | |
142 | gate_decimal_t b; | ||
143 | unsigned n; | ||
144 | |||
145 | ✗ | if (gate_decimal_compare(deci, &n2) < 0) | |
146 | { | ||
147 | ✗ | return; | |
148 | } | ||
149 | |||
150 | ✗ | for (n = 0; n < 8; ++n) | |
151 | { | ||
152 | ✗ | b.value = (deci->value / a.value) * GATE_DECIMAL_FACTOR; | |
153 | ✗ | a.value = (a.value + b.value) / 2; | |
154 | } | ||
155 | ✗ | deci->value = a.value; | |
156 | } | ||
157 | |||
158 | |||
159 | 528 | gate_bool_t gate_math_iszero(gate_real64_t num) | |
160 | { | ||
161 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 517 times.
|
528 | if (num < 0.0) |
162 | { | ||
163 | 11 | return (-num < DBL_EPSILON) ? true : false; | |
164 | } | ||
165 | else | ||
166 | { | ||
167 | 517 | return (num < DBL_EPSILON) ? true : false; | |
168 | } | ||
169 | } | ||
170 | 40 | gate_bool_t gate_math_iszerof(gate_real32_t num) | |
171 | { | ||
172 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 36 times.
|
40 | if (num < 0.0f) |
173 | { | ||
174 | 4 | return (-num < FLT_EPSILON) ? true : false; | |
175 | } | ||
176 | else | ||
177 | { | ||
178 | 36 | return (num < FLT_EPSILON) ? true : false; | |
179 | } | ||
180 | } | ||
181 | |||
182 | 31 | gate_bool_t gate_math_isnan(gate_real64_t num) | |
183 | { | ||
184 | 31 | volatile gate_real64_t tmp = num; | |
185 | 31 | return (tmp != num) ? true : false; | |
186 | } | ||
187 | 3 | gate_bool_t gate_math_isnanf(gate_real32_t num) | |
188 | { | ||
189 | 3 | volatile gate_real32_t tmp = num; | |
190 | 3 | return (tmp != num) ? true : false; | |
191 | } | ||
192 | |||
193 | 31 | int gate_math_isinfinite(gate_real64_t num) | |
194 | { | ||
195 | #if defined(DBL_MAX) | ||
196 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 30 times.
|
31 | if (num > DBL_MAX) |
197 | { | ||
198 | 1 | return 1; | |
199 | } | ||
200 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
|
30 | else if (num < -DBL_MAX) |
201 | { | ||
202 | ✗ | return -1; | |
203 | } | ||
204 | 30 | return 0; | |
205 | #else | ||
206 | static gate_real64_t const gate_math_infinite_pos = 1.0 / 0.0; | ||
207 | static gate_real64_t const gate_math_infinite_neg = -1.0 / 0.0; | ||
208 | if (num == gate_math_infinite_pos) | ||
209 | { | ||
210 | return 1; | ||
211 | } | ||
212 | else if (num == gate_math_infinite_neg) | ||
213 | { | ||
214 | return -1; | ||
215 | } | ||
216 | return 0; | ||
217 | #endif | ||
218 | } | ||
219 | 3 | int gate_math_isinfinitef(gate_real32_t num) | |
220 | { | ||
221 | #if defined(FLT_MAX) | ||
222 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
|
3 | if (num > FLT_MAX) |
223 | { | ||
224 | 1 | return 1; | |
225 | } | ||
226 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | else if (num < -FLT_MAX) |
227 | { | ||
228 | ✗ | return -1; | |
229 | } | ||
230 | 2 | return 0; | |
231 | #else | ||
232 | static gate_real32_t const gate_math_infinite_pos = 1.0f / 0.0f; | ||
233 | static gate_real32_t const gate_math_infinite_neg = -1.0f / 0.0f; | ||
234 | if (num == gate_math_infinite_pos) | ||
235 | { | ||
236 | return 1; | ||
237 | } | ||
238 | else if (num == gate_math_infinite_neg) | ||
239 | { | ||
240 | return -1; | ||
241 | } | ||
242 | return 0; | ||
243 | #endif | ||
244 | |||
245 | } | ||
246 | |||
247 | 4 | int gate_math_signum_i8(gate_int8_t num) | |
248 | { | ||
249 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | return (num < 0) ? -1 : ((num == 0) ? 0 : 1); |
250 | } | ||
251 | 4 | int gate_math_signum_i16(gate_int16_t num) | |
252 | { | ||
253 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | return (num < 0) ? -1 : ((num == 0) ? 0 : 1); |
254 | } | ||
255 | 4 | int gate_math_signum_i32(gate_int32_t num) | |
256 | { | ||
257 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | return (num < 0) ? -1 : ((num == 0) ? 0 : 1); |
258 | } | ||
259 | 4 | int gate_math_signum_i64(gate_int64_t num) | |
260 | { | ||
261 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | return (num < 0) ? -1 : ((num == 0) ? 0 : 1); |
262 | } | ||
263 | 4 | int gate_math_signum_r32(gate_real32_t num) | |
264 | { | ||
265 |
4/4✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
|
4 | return gate_math_iszerof(num) ? 0 : ((num < 0.0f) ? -1 : 1); |
266 | } | ||
267 | 4 | int gate_math_signum_r64(gate_real64_t num) | |
268 | { | ||
269 |
4/4✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
|
4 | return gate_math_iszero(num) ? 0 : ((num < 0.0) ? -1 : 1); |
270 | } | ||
271 | |||
272 | |||
273 | 3 | gate_int8_t gate_math_abs_i8(gate_int8_t num) | |
274 | { | ||
275 | 3 | return num < 0 ? -num : num; | |
276 | } | ||
277 | 3 | gate_int16_t gate_math_abs_i16(gate_int16_t num) | |
278 | { | ||
279 | 3 | return num < 0 ? -num : num; | |
280 | } | ||
281 | 41 | gate_int32_t gate_math_abs_i32(gate_int32_t num) | |
282 | { | ||
283 | 41 | return num < 0 ? -num : num; | |
284 | } | ||
285 | 3 | gate_int64_t gate_math_abs_i64(gate_int64_t num) | |
286 | { | ||
287 | 3 | return num < 0 ? -num : num; | |
288 | } | ||
289 | 6 | gate_real32_t gate_math_abs_r32(gate_real32_t num) | |
290 | { | ||
291 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
|
6 | return num < 0.0f ? -num : num; |
292 | } | ||
293 | 7 | gate_real64_t gate_math_abs_r64(gate_real64_t num) | |
294 | { | ||
295 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6 times.
|
7 | return num < 0.0 ? -num : num; |
296 | } | ||
297 | |||
298 | #define gate_math_min_type(type, va_type, count) \ | ||
299 | type ret = 0; \ | ||
300 | type tmp; \ | ||
301 | va_list vl; \ | ||
302 | if(count != 0) \ | ||
303 | { \ | ||
304 | va_start(vl, count); \ | ||
305 | ret = (type)va_arg(vl, va_type); \ | ||
306 | while(--count) \ | ||
307 | { \ | ||
308 | tmp = (type)va_arg(vl, va_type); \ | ||
309 | if(tmp < ret) \ | ||
310 | { \ | ||
311 | ret = tmp; \ | ||
312 | } \ | ||
313 | } \ | ||
314 | va_end(vl); \ | ||
315 | } \ | ||
316 | return ret | ||
317 | |||
318 | #define gate_math_max_type(type, va_type, count) \ | ||
319 | type ret = 0; \ | ||
320 | type tmp; \ | ||
321 | va_list vl; \ | ||
322 | if(count != 0) \ | ||
323 | { \ | ||
324 | va_start(vl, count); \ | ||
325 | ret = (type)va_arg(vl, va_type); \ | ||
326 | while(--count) \ | ||
327 | { \ | ||
328 | tmp = (type)va_arg(vl, va_type); \ | ||
329 | if(tmp > ret) \ | ||
330 | { \ | ||
331 | ret = tmp; \ | ||
332 | } \ | ||
333 | } \ | ||
334 | va_end(vl); \ | ||
335 | } \ | ||
336 | return ret | ||
337 | |||
338 | |||
339 | 1 | gate_int16_t gate_math_min_i16(gate_size_t count, ...) | |
340 | { | ||
341 |
5/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 1 times.
|
3 | gate_math_min_type(gate_int16_t, int, count); |
342 | } | ||
343 | 1 | gate_int32_t gate_math_min_i32(gate_size_t count, ...) | |
344 | { | ||
345 |
5/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 1 times.
|
3 | gate_math_min_type(gate_int32_t, gate_int32_t, count); |
346 | } | ||
347 | 1 | gate_int64_t gate_math_min_i64(gate_size_t count, ...) | |
348 | { | ||
349 |
5/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 1 times.
|
3 | gate_math_min_type(gate_int64_t, gate_int64_t, count); |
350 | } | ||
351 | 1 | gate_real32_t gate_math_min_r32(gate_size_t count, ...) | |
352 | { | ||
353 |
5/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 1 times.
|
3 | gate_math_min_type(gate_real32_t, gate_real64_t, count); |
354 | } | ||
355 | 1 | gate_real64_t gate_math_min_r64(gate_size_t count, ...) | |
356 | { | ||
357 |
5/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 1 times.
|
3 | gate_math_min_type(gate_real64_t, gate_real64_t, count); |
358 | } | ||
359 | |||
360 | 1 | gate_int16_t gate_math_max_i16(gate_size_t count, ...) | |
361 | { | ||
362 |
5/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 1 times.
|
3 | gate_math_max_type(gate_int16_t, int, count); |
363 | } | ||
364 | 1 | gate_int32_t gate_math_max_i32(gate_size_t count, ...) | |
365 | { | ||
366 |
5/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 1 times.
|
3 | gate_math_max_type(gate_int32_t, gate_int32_t, count); |
367 | } | ||
368 | 1 | gate_int64_t gate_math_max_i64(gate_size_t count, ...) | |
369 | { | ||
370 |
5/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 1 times.
|
3 | gate_math_max_type(gate_int64_t, gate_int64_t, count); |
371 | } | ||
372 | 1 | gate_real32_t gate_math_max_r32(gate_size_t count, ...) | |
373 | { | ||
374 |
5/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 1 times.
|
3 | gate_math_max_type(gate_real32_t, gate_real64_t, count); |
375 | } | ||
376 | 1 | gate_real64_t gate_math_max_r64(gate_size_t count, ...) | |
377 | { | ||
378 |
5/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 1 times.
|
3 | gate_math_max_type(gate_real64_t, gate_real64_t, count); |
379 | } | ||
380 | 3 | gate_uint8_t gate_math_decimal_length(gate_real64_t value) | |
381 | { | ||
382 | 3 | gate_uint8_t len = 0; | |
383 | 3 | gate_real64_t factor = 1.0; | |
384 | gate_real64_t test_value; | ||
385 | gate_real64_t diff; | ||
386 | |||
387 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (value < 0.0) |
388 | { | ||
389 | ✗ | value = -value; | |
390 | } | ||
391 | |||
392 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | while (len < 20) |
393 | { | ||
394 | 15 | test_value = value * factor; | |
395 | 15 | diff = (test_value - ((gate_real64_t)(gate_int64_t)test_value)); | |
396 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 12 times.
|
15 | if (gate_math_iszero(diff)) |
397 | { | ||
398 | 3 | break; | |
399 | } | ||
400 | 12 | factor *= 10.0; | |
401 | 12 | ++len; | |
402 | } | ||
403 | 3 | return len; | |
404 | } | ||
405 | |||
406 | 19 | gate_real64_t gate_math_deg2rad(gate_real64_t value) | |
407 | { | ||
408 | 19 | return value * GATE_MATH_CONST_PI / 180.0; | |
409 | } | ||
410 | 7 | gate_real64_t gate_math_rad2deg(gate_real64_t value) | |
411 | { | ||
412 | 7 | return value * 180.0 / GATE_MATH_CONST_PI; | |
413 | } | ||
414 | |||
415 | ✗ | gate_int64_t gate_math_pow_i64(gate_int64_t base, gate_uint16_t exp) | |
416 | { | ||
417 | gate_uint8_t n; | ||
418 | ✗ | gate_int64_t ret = 1; | |
419 | ✗ | for (n = 0; n != exp; ++n) | |
420 | { | ||
421 | ✗ | ret *= base; | |
422 | } | ||
423 | ✗ | return ret; | |
424 | } | ||
425 | |||
426 | ✗ | gate_real64_t gate_math_pow_iexp(gate_real64_t base, gate_uint16_t exp) | |
427 | { | ||
428 | gate_uint16_t n; | ||
429 | ✗ | gate_real64_t ret = 1.0; | |
430 | ✗ | for (n = 0; n != exp; ++n) | |
431 | { | ||
432 | ✗ | ret *= base; | |
433 | } | ||
434 | ✗ | return ret; | |
435 | } | ||
436 | |||
437 | 5 | gate_real64_t gate_math_acosh(gate_real64_t value) | |
438 | { | ||
439 | 5 | return gate_math_log(value + gate_math_sqrt(value * value - 1.0)); | |
440 | } | ||
441 | 6 | gate_real64_t gate_math_asinh(gate_real64_t value) | |
442 | { | ||
443 | 6 | return gate_math_log(value + gate_math_sqrt(value * value + 1.0)); | |
444 | } | ||
445 | 6 | gate_real64_t gate_math_atanh(gate_real64_t value) | |
446 | { | ||
447 | 6 | return gate_math_log((1.0 + value) / (1.0 - value)) / 2.0; | |
448 | } | ||
449 | |||
450 | |||
451 | |||
452 | |||
453 | |||
454 | |||
455 | |||
456 | #if defined(GATE_CORE_MATH_STD_IMPL) | ||
457 | |||
458 | #include <math.h> | ||
459 | |||
460 | 45 | gate_real64_t gate_math_cos(gate_real64_t value) | |
461 | { | ||
462 | 45 | return cos(value); | |
463 | } | ||
464 | 9 | gate_real64_t gate_math_sin(gate_real64_t value) | |
465 | { | ||
466 | 9 | return sin(value); | |
467 | } | ||
468 | 7 | gate_real64_t gate_math_tan(gate_real64_t value) | |
469 | { | ||
470 | 7 | return tan(value); | |
471 | } | ||
472 | 6 | gate_real64_t gate_math_acos(gate_real64_t value) | |
473 | { | ||
474 | 6 | return acos(value); | |
475 | } | ||
476 | 9 | gate_real64_t gate_math_asin(gate_real64_t value) | |
477 | { | ||
478 | 9 | return asin(value); | |
479 | } | ||
480 | 10 | gate_real64_t gate_math_atan(gate_real64_t value) | |
481 | { | ||
482 | 10 | return atan(value); | |
483 | } | ||
484 | 2 | gate_real64_t gate_math_atan2(gate_real64_t y, gate_real64_t x) | |
485 | { | ||
486 | 2 | return atan2(y, x); | |
487 | } | ||
488 | 6 | gate_real64_t gate_math_cosh(gate_real64_t value) | |
489 | { | ||
490 | 6 | return cosh(value); | |
491 | } | ||
492 | 6 | gate_real64_t gate_math_sinh(gate_real64_t value) | |
493 | { | ||
494 | 6 | return sinh(value); | |
495 | } | ||
496 | 6 | gate_real64_t gate_math_tanh(gate_real64_t value) | |
497 | { | ||
498 | 6 | return tanh(value); | |
499 | } | ||
500 | |||
501 | 7 | gate_real64_t gate_math_exp(gate_real64_t value) | |
502 | { | ||
503 | 7 | return exp(value); | |
504 | } | ||
505 | 2 | gate_real64_t gate_math_frexp(gate_real64_t value, int* exp) | |
506 | { | ||
507 | 2 | return frexp(value, exp); | |
508 | } | ||
509 | ✗ | gate_real64_t gate_math_ldexp(gate_real64_t value, int exp) | |
510 | { | ||
511 | ✗ | return ldexp(value, exp); | |
512 | } | ||
513 | 23 | gate_real64_t gate_math_log(gate_real64_t value) | |
514 | { | ||
515 | 23 | return log(value); | |
516 | } | ||
517 | 6 | gate_real64_t gate_math_log10(gate_real64_t value) | |
518 | { | ||
519 | 6 | return log10(value); | |
520 | } | ||
521 | 2 | gate_real64_t gate_math_modf(gate_real64_t value, double* intpart) | |
522 | { | ||
523 | 2 | return modf(value, intpart); | |
524 | } | ||
525 | |||
526 | 2 | gate_real64_t gate_math_pow(gate_real64_t base, gate_real64_t exp) | |
527 | { | ||
528 | 2 | return pow(base, exp); | |
529 | } | ||
530 | 21 | gate_real64_t gate_math_sqrt(gate_real64_t value) | |
531 | { | ||
532 | 21 | return sqrt(value); | |
533 | } | ||
534 | |||
535 | 7 | gate_real64_t gate_math_ceil(gate_real64_t value) | |
536 | { | ||
537 | 7 | return ceil(value); | |
538 | } | ||
539 | 7 | gate_real64_t gate_math_floor(gate_real64_t value) | |
540 | { | ||
541 | 7 | return floor(value); | |
542 | } | ||
543 | |||
544 | |||
545 | #endif /* GATE_CORE_MATH_STD_IMPL */ | ||
546 | |||
547 | |||
548 | |||
549 | #if defined(GATE_CORE_MATH_EFI_IMPL) | ||
550 | |||
551 | static gate_real64_t normalize_angle(gate_real64_t angle) | ||
552 | { | ||
553 | while (angle <= -GATE_MATH_CONST_PI) | ||
554 | { | ||
555 | angle += GATE_MATH_CONST_PI; | ||
556 | } | ||
557 | while (angle > GATE_MATH_CONST_PI) | ||
558 | { | ||
559 | angle -= GATE_MATH_CONST_PI; | ||
560 | } | ||
561 | return angle; | ||
562 | } | ||
563 | |||
564 | gate_real64_t gate_math_cos(gate_real64_t value) | ||
565 | { | ||
566 | static gate_real64_t const n2 = 2.0; | ||
567 | static gate_real64_t const n4 = 24.0; | ||
568 | static gate_real64_t const n6 = 720.0; | ||
569 | static gate_real64_t const n8 = 40320.0; | ||
570 | static gate_real64_t const n10 = 3628800.0; | ||
571 | static gate_real64_t const n12 = 479001600.0; | ||
572 | gate_real64_t const x = normalize_angle(value); | ||
573 | gate_real64_t const x2 = x * x; | ||
574 | gate_real64_t const x4 = x2 * x * x; | ||
575 | gate_real64_t const x6 = x4 * x * x; | ||
576 | gate_real64_t const x8 = x6 * x * x; | ||
577 | gate_real64_t const x10 = x8 * x * x; | ||
578 | gate_real64_t const x12 = x10 * x * x; | ||
579 | |||
580 | return 1 - x2 / n2 + x4 / n4 - x6 / n6 + x8 / n8 - x10 / n10 + x12 / n12; | ||
581 | } | ||
582 | |||
583 | |||
584 | |||
585 | gate_real64_t gate_math_sin(gate_real64_t value) | ||
586 | { | ||
587 | static gate_real64_t const n3 = 6.0; | ||
588 | static gate_real64_t const n5 = 120.0; | ||
589 | static gate_real64_t const n7 = 5040.0; | ||
590 | static gate_real64_t const n9 = 362880.0; | ||
591 | static gate_real64_t const n11 = 39916800.0; | ||
592 | static gate_real64_t const n13 = 6227020800.0; | ||
593 | gate_real64_t const x = normalize_angle(value); | ||
594 | gate_real64_t const x3 = x * x * x; | ||
595 | gate_real64_t const x5 = x3 * x * x; | ||
596 | gate_real64_t const x7 = x5 * x * x; | ||
597 | gate_real64_t const x9 = x7 * x * x; | ||
598 | gate_real64_t const x11 = x9 * x * x; | ||
599 | gate_real64_t const x13 = x11 * x * x; | ||
600 | |||
601 | return x - x3 / n3 + x5 / n5 - x7 / n7 + x9 / n9 - x11 / n11 + x13 / n13; | ||
602 | } | ||
603 | gate_real64_t gate_math_tan(gate_real64_t value) | ||
604 | { | ||
605 | return gate_math_sin(value) / gate_math_cos(value); | ||
606 | } | ||
607 | |||
608 | gate_real64_t gate_math_asin(gate_real64_t value) | ||
609 | { | ||
610 | /* https://de.wikipedia.org/wiki/Arkussinus_und_Arkuskosinus#Reihenentwicklungen */ | ||
611 | |||
612 | static double const ret_0_96 = 1.2870022176; | ||
613 | /*static double const ret_1_00 = GATE_MATH_CONST_PI * 0.5;*/ | ||
614 | static double const diff_1_00 = GATE_MATH_CONST_PI * 0.5 - 1.2870022176; | ||
615 | |||
616 | static unsigned const n_max = 107; /* quite OK up to 0.96 */ | ||
617 | double factor; | ||
618 | unsigned n; | ||
619 | |||
620 | double x = value; | ||
621 | double ret = x; | ||
622 | double a = 1; | ||
623 | double b = 1; | ||
624 | |||
625 | if (value > 0.96) | ||
626 | { | ||
627 | /* iterative solution becomes unstable for value > 0.96 | ||
628 | just apply a quick and dirty linear patch */ | ||
629 | factor = (value - 0.96) / (1.00 - 0.96); | ||
630 | ret = ret_0_96 + diff_1_00 * factor; | ||
631 | } | ||
632 | else | ||
633 | { | ||
634 | for (n = 3; n != n_max; n += 2) | ||
635 | { | ||
636 | x *= value * value; | ||
637 | a *= ((double)n - 2.0); | ||
638 | b *= ((double)n - 1.0); | ||
639 | ret += a * x / (b * (double)n); | ||
640 | } | ||
641 | } | ||
642 | |||
643 | return ret; | ||
644 | } | ||
645 | gate_real64_t gate_math_acos(gate_real64_t value) | ||
646 | { | ||
647 | /* https://stackoverflow.com/questions/3380628/fast-arc-cos-algorithm/20914630 */ | ||
648 | /* return (-0.69813170079773212 * value * value - 0.87266462599716477) * value + 1.5707963267948966; */ | ||
649 | return GATE_MATH_CONST_PI * 0.5 - gate_math_asin(value); | ||
650 | } | ||
651 | gate_real64_t gate_math_atan(gate_real64_t value) | ||
652 | { | ||
653 | gate_real64_t ret; | ||
654 | ret = gate_math_asin(value / gate_math_sqrt(1 + value * value)); | ||
655 | return ret; | ||
656 | } | ||
657 | gate_real64_t gate_math_atan2(gate_real64_t y, gate_real64_t x) | ||
658 | { | ||
659 | /* TODO */ | ||
660 | return 0.0; | ||
661 | } | ||
662 | gate_real64_t gate_math_sinh(gate_real64_t value) | ||
663 | { | ||
664 | return 0.5 * (gate_math_exp(value) - gate_math_exp(-value)); | ||
665 | } | ||
666 | gate_real64_t gate_math_cosh(gate_real64_t value) | ||
667 | { | ||
668 | return 0.5 * (gate_math_exp(value) + gate_math_exp(-value)); | ||
669 | } | ||
670 | gate_real64_t gate_math_tanh(gate_real64_t value) | ||
671 | { | ||
672 | return gate_math_sinh(value) / gate_math_cosh(value); | ||
673 | } | ||
674 | |||
675 | gate_real64_t gate_math_exp(gate_real64_t value) | ||
676 | { | ||
677 | /* https://www.pseudorandom.com/implementing-exp */ | ||
678 | gate_real64_t x0, tn; | ||
679 | gate_int64_t i, n; | ||
680 | |||
681 | if (gate_math_iszero(value)) | ||
682 | { | ||
683 | return 1.0; | ||
684 | } | ||
685 | x0 = gate_math_abs_r64(value); | ||
686 | tn = 1.0; | ||
687 | n = 12; | ||
688 | n *= (gate_int64_t)gate_math_ceil(x0 * GATE_MATH_CONST_E); | ||
689 | for (i = n; i > 0; i--) | ||
690 | { | ||
691 | tn = tn * (x0 / i) + 1.0; | ||
692 | } | ||
693 | |||
694 | if (value < 0.0) | ||
695 | { | ||
696 | tn = 1.0 / tn; | ||
697 | } | ||
698 | return tn; | ||
699 | } | ||
700 | gate_real64_t gate_math_frexp(gate_real64_t value, int* exp) | ||
701 | { | ||
702 | /* TODO */ | ||
703 | return 0.0; | ||
704 | } | ||
705 | gate_real64_t gate_math_ldexp(gate_real64_t value, int exp) | ||
706 | { | ||
707 | /* TODO */ | ||
708 | return 0.0; | ||
709 | } | ||
710 | |||
711 | static unsigned msb(unsigned v) | ||
712 | { | ||
713 | unsigned ret = 0; | ||
714 | while (v >>= 1) | ||
715 | { | ||
716 | ret++; | ||
717 | } | ||
718 | return ret; | ||
719 | } | ||
720 | |||
721 | static float log_n(float value) | ||
722 | { | ||
723 | /* https://stackoverflow.com/questions/9799041/efficient-implementation-of-natural-logarithm-ln-and-exponentiation */ | ||
724 | int log2; | ||
725 | float divisor, x, result; | ||
726 | |||
727 | log2 = msb((int)value); // See: https://stackoverflow.com/a/4970859/6630230 | ||
728 | divisor = (float)(1 << log2); | ||
729 | x = value / divisor; | ||
730 | result = -1.7417939f + (2.8212026f + (-1.4699568f + (0.44717955f - 0.056570851f * x) * x) * x) * x; | ||
731 | result += ((float)log2) * 0.69314718f; | ||
732 | |||
733 | return result; | ||
734 | } | ||
735 | |||
736 | |||
737 | gate_real64_t gate_math_log(gate_real64_t value) | ||
738 | { | ||
739 | return (gate_real64_t)log_n((float)value); | ||
740 | } | ||
741 | gate_real64_t gate_math_log10(gate_real64_t value) | ||
742 | { | ||
743 | return gate_math_log(value) / gate_math_log(10.0); | ||
744 | } | ||
745 | gate_real64_t gate_math_modf(gate_real64_t value, gate_real64_t* intpart) | ||
746 | { | ||
747 | gate_real64_t ret; | ||
748 | gate_uint64_t ui; | ||
749 | if (value < 0.0) | ||
750 | { | ||
751 | ui = (gate_uint64_t)-value; | ||
752 | ret = -value - (gate_real64_t)ui; | ||
753 | if (intpart) | ||
754 | { | ||
755 | *intpart = -((gate_real64_t)ui); | ||
756 | } | ||
757 | } | ||
758 | else | ||
759 | { | ||
760 | ui = (gate_uint64_t)value; | ||
761 | ret = value - (gate_real64_t)ui; | ||
762 | if (intpart) | ||
763 | { | ||
764 | *intpart = (gate_real64_t)ui; | ||
765 | } | ||
766 | } | ||
767 | return ret; | ||
768 | } | ||
769 | |||
770 | gate_real64_t gate_math_pow(gate_real64_t base, gate_real64_t exp) | ||
771 | { | ||
772 | if (exp < 0.0) | ||
773 | { | ||
774 | return 1.0 / gate_math_pow_iexp(base, (gate_uint16_t)-exp); | ||
775 | } | ||
776 | else | ||
777 | { | ||
778 | return gate_math_pow_iexp(base, (gate_uint16_t)exp); | ||
779 | } | ||
780 | return 0.0; | ||
781 | } | ||
782 | |||
783 | union f_rsqrt_helper | ||
784 | { | ||
785 | float f; | ||
786 | gate_uint32_t i; | ||
787 | }; | ||
788 | |||
789 | |||
790 | union d_rsqrt_helper | ||
791 | { | ||
792 | double d; | ||
793 | gate_uint64_t i; | ||
794 | }; | ||
795 | |||
796 | /* https://en.wikipedia.org/wiki/Fast_inverse_square_root */ | ||
797 | /* https://stackoverflow.com/questions/11644441/fast-inverse-square-root-on-x64/11644533 */ | ||
798 | static float f_rsqrt(float number) | ||
799 | { | ||
800 | static const float threehalfs = 1.5F; | ||
801 | const float x2 = number * 0.5F; | ||
802 | |||
803 | union f_rsqrt_helper conv; | ||
804 | conv.f = number; | ||
805 | conv.i = 0x5f3759df - (conv.i >> 1); | ||
806 | conv.f *= threehalfs - (x2 * conv.f * conv.f); | ||
807 | return conv.f; | ||
808 | } | ||
809 | |||
810 | static double d_rsqrt(double number) | ||
811 | { | ||
812 | double y = number; | ||
813 | double x2 = y * 0.5; | ||
814 | |||
815 | union d_rsqrt_helper conv; | ||
816 | conv.d = y; | ||
817 | conv.i = 0x5fe6eb50c7b537a9 - (conv.i >> 1); | ||
818 | y = conv.d; | ||
819 | y = y * (1.5 - (x2 * y * y)); | ||
820 | y = y * (1.5 - (x2 * y * y)); | ||
821 | return y; | ||
822 | } | ||
823 | |||
824 | |||
825 | gate_real64_t gate_math_sqrt(gate_real64_t value) | ||
826 | { | ||
827 | double num = gate_math_abs_r64((double)value); | ||
828 | return (gate_real64_t)(1.0 / d_rsqrt(num)); | ||
829 | } | ||
830 | |||
831 | gate_real64_t gate_math_ceil(gate_real64_t value) | ||
832 | { | ||
833 | gate_int64_t i = (gate_int64_t)value; | ||
834 | gate_real64_t diff = value - (gate_real64_t)i; | ||
835 | if (!gate_math_iszero(diff)) | ||
836 | { | ||
837 | if (value >= 0.0) | ||
838 | { | ||
839 | i = (gate_int64_t)(value + 1.0); | ||
840 | } | ||
841 | else | ||
842 | { | ||
843 | i = -(gate_int64_t)(-value); | ||
844 | } | ||
845 | } | ||
846 | return (gate_real64_t)i; | ||
847 | } | ||
848 | gate_real64_t gate_math_floor(gate_real64_t value) | ||
849 | { | ||
850 | gate_int64_t i = (gate_int64_t)value; | ||
851 | gate_real64_t diff = value - (gate_real64_t)i; | ||
852 | if (!gate_math_iszero(diff)) | ||
853 | { | ||
854 | if (value >= 0.0) | ||
855 | { | ||
856 | i = (gate_int64_t)(value); | ||
857 | } | ||
858 | else | ||
859 | { | ||
860 | i = -(gate_int64_t)(-value + 1.0); | ||
861 | } | ||
862 | } | ||
863 | return (gate_real64_t)i; | ||
864 | } | ||
865 | |||
866 | #endif /* GATE_CORE_MATH_EFI_IMPL */ | ||
867 | |||
868 |