GCC Code Coverage Report


Directory: src/gate/
File: src/gate/mathematics.c
Date: 2026-09-21 06:26:40
Exec Total Coverage
Lines: 164 215 76.3%
Functions: 64 77 83.1%
Branches: 90 112 80.4%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright (c) 2018-2026, 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 2 void gate_decimal_init(gate_decimal_t* deci, gate_int32_t int_num, gate_uint32_t micro_num)
46 {
47 2 deci->value = (gate_decimal_primitive_t)(int_num * GATE_DECIMAL_FACTOR);
48 2 deci->value += (gate_decimal_primitive_t)(micro_num % GATE_DECIMAL_FACTOR);
49 2 }
50 1 gate_int32_t gate_decimal_get_int(gate_decimal_t const* deci)
51 {
52 1 return (gate_int32_t)(deci->value / GATE_DECIMAL_FACTOR);
53 }
54 1 gate_uint32_t gate_decimal_get_micro(gate_decimal_t const* deci)
55 {
56
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (deci->value < 0)
57 {
58 return (gate_uint32_t)((-deci->value) % GATE_DECIMAL_FACTOR);
59 }
60 else
61 {
62 1 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 5 int gate_decimal_compare(gate_decimal_t const* a, gate_decimal_t const* b)
71 {
72
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 if (a->value < b->value)
73 {
74 2 return -1;
75 }
76
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 else if (a->value > b->value)
77 {
78 3 return 1;
79 }
80 return 0;
81 }
82
83
84 1 void gate_decimal_add_int(gate_decimal_t* deci, gate_int32_t value)
85 {
86 1 deci->value += (gate_decimal_primitive_t)value * GATE_DECIMAL_FACTOR;
87 1 }
88 1 void gate_decimal_sub_int(gate_decimal_t* deci, gate_int32_t value)
89 {
90 1 deci->value -= (gate_decimal_primitive_t)value * GATE_DECIMAL_FACTOR;
91 1 }
92 1 void gate_decimal_mul_int(gate_decimal_t* deci, gate_int32_t value)
93 {
94 1 deci->value *= (gate_decimal_primitive_t)value;
95 1 }
96 1 void gate_decimal_div_int(gate_decimal_t* deci, gate_int32_t value)
97 {
98 1 deci->value /= (gate_decimal_primitive_t)value;
99 1 }
100
101 1 void gate_decimal_add_dec(gate_decimal_t* deci, gate_decimal_t const* ptr_value)
102 {
103 1 deci->value += ptr_value->value;
104 1 }
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 491 gate_bool_t gate_math_iszero(gate_real64_t num)
160 {
161
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 471 times.
491 if (num < 0.0)
162 {
163 20 return (-num < DBL_EPSILON) ? true : false;
164 }
165 else
166 {
167 471 return (num < DBL_EPSILON) ? true : false;
168 }
169 }
170 2362 gate_bool_t gate_math_iszerof(gate_real32_t num)
171 {
172
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2358 times.
2362 if (num < 0.0f)
173 {
174 4 return (-num < FLT_EPSILON) ? true : false;
175 }
176 else
177 {
178 2358 return (num < FLT_EPSILON) ? true : false;
179 }
180 }
181
182 381 gate_bool_t gate_math_isnan(gate_real64_t num)
183 {
184 381 volatile gate_real64_t tmp = num;
185 381 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 gate_real32_t gate_math_build_nanf(void)
194 {
195 #if !defined(NAN)
196 static gate_real32_t volatile const zero = 0.0f;
197 return (zero / zero);
198 #else
199 return NAN;
200 #endif
201 }
202
203 gate_real64_t gate_math_build_nan(void)
204 {
205 #if !defined(NAN)
206 static gate_real64_t volatile const zero = 0.0;
207 return (zero / zero);
208 #else
209 return NAN;
210 #endif
211 }
212
213
214 381 int gate_math_isinfinite(gate_real64_t num)
215 {
216 #if defined(DBL_MAX)
217
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 380 times.
381 if (num > DBL_MAX)
218 {
219 1 return 1;
220 }
221
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 380 times.
380 else if (num < -DBL_MAX)
222 {
223 return -1;
224 }
225 380 return 0;
226 #else
227 #define gate_math_infinite_pos (1.0 / 0.0)
228 #define gate_math_infinite_neg (-1.0 / 0.0)
229 if (num == gate_math_infinite_pos)
230 {
231 return 1;
232 }
233 else if (num == gate_math_infinite_neg)
234 {
235 return -1;
236 }
237 return 0;
238 #endif
239 }
240 3 int gate_math_isinfinitef(gate_real32_t num)
241 {
242 #if defined(FLT_MAX)
243
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (num > FLT_MAX)
244 {
245 1 return 1;
246 }
247
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 else if (num < -FLT_MAX)
248 {
249 return -1;
250 }
251 2 return 0;
252 #else
253 static gate_real32_t const gate_math_infinite_pos = 1.0f / 0.0f;
254 static gate_real32_t const gate_math_infinite_neg = -1.0f / 0.0f;
255 if (num == gate_math_infinite_pos)
256 {
257 return 1;
258 }
259 else if (num == gate_math_infinite_neg)
260 {
261 return -1;
262 }
263 return 0;
264 #endif
265
266 }
267
268 4 int gate_math_signum_i8(gate_int8_t num)
269 {
270
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 return (num < 0) ? -1 : ((num == 0) ? 0 : 1);
271 }
272 4 int gate_math_signum_i16(gate_int16_t num)
273 {
274
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 return (num < 0) ? -1 : ((num == 0) ? 0 : 1);
275 }
276 4 int gate_math_signum_i32(gate_int32_t num)
277 {
278
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 return (num < 0) ? -1 : ((num == 0) ? 0 : 1);
279 }
280 4 int gate_math_signum_i64(gate_int64_t num)
281 {
282
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 return (num < 0) ? -1 : ((num == 0) ? 0 : 1);
283 }
284 4 int gate_math_signum_r32(gate_real32_t num)
285 {
286
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);
287 }
288 4 int gate_math_signum_r64(gate_real64_t num)
289 {
290
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);
291 }
292
293
294 3 gate_int8_t gate_math_abs_i8(gate_int8_t num)
295 {
296 3 return num < 0 ? -num : num;
297 }
298 819 gate_int16_t gate_math_abs_i16(gate_int16_t num)
299 {
300 819 return num < 0 ? -num : num;
301 }
302 166 gate_int32_t gate_math_abs_i32(gate_int32_t num)
303 {
304 166 return num < 0 ? -num : num;
305 }
306 3 gate_int64_t gate_math_abs_i64(gate_int64_t num)
307 {
308 3 return num < 0 ? -num : num;
309 }
310 6 gate_real32_t gate_math_abs_r32(gate_real32_t num)
311 {
312
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
6 return num < 0.0f ? -num : num;
313 }
314 7 gate_real64_t gate_math_abs_r64(gate_real64_t num)
315 {
316
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6 times.
7 return num < 0.0 ? -num : num;
317 }
318
319 #define gate_math_min_type(type, va_type, count) \
320 type ret = 0; \
321 type tmp; \
322 va_list vl; \
323 if(count != 0) \
324 { \
325 va_start(vl, count); \
326 ret = (type)va_arg(vl, va_type); \
327 while(--count) \
328 { \
329 tmp = (type)va_arg(vl, va_type); \
330 if(tmp < ret) \
331 { \
332 ret = tmp; \
333 } \
334 } \
335 va_end(vl); \
336 } \
337 return ret
338
339 #define gate_math_max_type(type, va_type, count) \
340 type ret = 0; \
341 type tmp; \
342 va_list vl; \
343 if(count != 0) \
344 { \
345 va_start(vl, count); \
346 ret = (type)va_arg(vl, va_type); \
347 while(--count) \
348 { \
349 tmp = (type)va_arg(vl, va_type); \
350 if(tmp > ret) \
351 { \
352 ret = tmp; \
353 } \
354 } \
355 va_end(vl); \
356 } \
357 return ret
358
359
360 1 gate_int16_t gate_math_min_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_min_type(gate_int16_t, int, count);
363 }
364 1 gate_int32_t gate_math_min_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_min_type(gate_int32_t, gate_int32_t, count);
367 }
368 1 gate_int64_t gate_math_min_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_min_type(gate_int64_t, gate_int64_t, count);
371 }
372 1 gate_real32_t gate_math_min_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_min_type(gate_real32_t, gate_real64_t, count);
375 }
376 1 gate_real64_t gate_math_min_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_min_type(gate_real64_t, gate_real64_t, count);
379 }
380
381 273 gate_int16_t gate_math_max_i16(gate_size_t count, ...)
382 {
383
5/6
✓ Branch 0 taken 273 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 242 times.
✓ Branch 5 taken 304 times.
✓ Branch 6 taken 546 times.
✓ Branch 7 taken 273 times.
819 gate_math_max_type(gate_int16_t, int, count);
384 }
385 1 gate_int32_t gate_math_max_i32(gate_size_t count, ...)
386 {
387
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);
388 }
389 1 gate_int64_t gate_math_max_i64(gate_size_t count, ...)
390 {
391
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);
392 }
393 1 gate_real32_t gate_math_max_r32(gate_size_t count, ...)
394 {
395
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);
396 }
397 1 gate_real64_t gate_math_max_r64(gate_size_t count, ...)
398 {
399
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);
400 }
401 7 gate_uint8_t gate_math_decimal_length(gate_real64_t value)
402 {
403 7 gate_uint8_t len = 0;
404 7 gate_real64_t factor = 1.0;
405 gate_real64_t test_value;
406 gate_real64_t diff;
407
408
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (value < 0.0)
409 {
410 value = -value;
411 }
412
413
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 while (len < 20)
414 {
415 30 test_value = value * factor;
416 30 diff = (test_value - ((gate_real64_t)(gate_int64_t)test_value));
417
2/2
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 23 times.
30 if (gate_math_iszero(diff))
418 {
419 7 break;
420 }
421 23 factor *= 10.0;
422 23 ++len;
423 }
424 7 return len;
425 }
426
427 27 gate_real64_t gate_math_deg2rad(gate_real64_t value)
428 {
429 27 return value * GATE_MATH_CONST_PI / 180.0;
430 }
431 19 gate_real64_t gate_math_rad2deg(gate_real64_t value)
432 {
433 19 return value * 180.0 / GATE_MATH_CONST_PI;
434 }
435
436 3 gate_int64_t gate_math_pow_i64(gate_int64_t base, gate_uint16_t exp)
437 {
438 gate_uint8_t n;
439 3 gate_int64_t ret = 1;
440
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 3 times.
60 for (n = 0; n != exp; ++n)
441 {
442 57 ret *= base;
443 }
444 3 return ret;
445 }
446
447 gate_real64_t gate_math_pow_iexp(gate_real64_t base, gate_uint16_t exp)
448 {
449 gate_uint16_t n;
450 gate_real64_t ret = 1.0;
451 for (n = 0; n != exp; ++n)
452 {
453 ret *= base;
454 }
455 return ret;
456 }
457
458 5 gate_real64_t gate_math_acosh(gate_real64_t value)
459 {
460 5 return gate_math_log(value + gate_math_sqrt(value * value - 1.0));
461 }
462 6 gate_real64_t gate_math_asinh(gate_real64_t value)
463 {
464 6 return gate_math_log(value + gate_math_sqrt(value * value + 1.0));
465 }
466 6 gate_real64_t gate_math_atanh(gate_real64_t value)
467 {
468 6 return gate_math_log((1.0 + value) / (1.0 - value)) / 2.0;
469 }
470
471
472
473
474
475
476
477 #if defined(GATE_CORE_MATH_STD_IMPL)
478
479 #include <math.h>
480
481 42 gate_real64_t gate_math_cos(gate_real64_t value)
482 {
483 42 return cos(value);
484 }
485 9 gate_real64_t gate_math_sin(gate_real64_t value)
486 {
487 9 return sin(value);
488 }
489 11 gate_real64_t gate_math_tan(gate_real64_t value)
490 {
491 11 return tan(value);
492 }
493 6 gate_real64_t gate_math_acos(gate_real64_t value)
494 {
495 6 return acos(value);
496 }
497 9 gate_real64_t gate_math_asin(gate_real64_t value)
498 {
499 9 return asin(value);
500 }
501 16 gate_real64_t gate_math_atan(gate_real64_t value)
502 {
503 16 return atan(value);
504 }
505 2 gate_real64_t gate_math_atan2(gate_real64_t y, gate_real64_t x)
506 {
507 2 return atan2(y, x);
508 }
509 6 gate_real64_t gate_math_cosh(gate_real64_t value)
510 {
511 6 return cosh(value);
512 }
513 6 gate_real64_t gate_math_sinh(gate_real64_t value)
514 {
515 6 return sinh(value);
516 }
517 6 gate_real64_t gate_math_tanh(gate_real64_t value)
518 {
519 6 return tanh(value);
520 }
521
522 13 gate_real64_t gate_math_exp(gate_real64_t value)
523 {
524 13 return exp(value);
525 }
526 2 gate_real64_t gate_math_frexp(gate_real64_t value, int* exp)
527 {
528 2 return frexp(value, exp);
529 }
530 gate_real64_t gate_math_ldexp(gate_real64_t value, int exp)
531 {
532 return ldexp(value, exp);
533 }
534 26 gate_real64_t gate_math_log(gate_real64_t value)
535 {
536 26 return log(value);
537 }
538 6 gate_real64_t gate_math_log2(gate_real64_t value)
539 {
540 static const gate_real64_t log2inverse = 1.4426950408889634;
541 6 return log(value) * log2inverse;
542 }
543 6 gate_real64_t gate_math_log10(gate_real64_t value)
544 {
545 6 return log10(value);
546 }
547 2 gate_real64_t gate_math_modf(gate_real64_t value, double* intpart)
548 {
549 2 return modf(value, intpart);
550 }
551
552 2 gate_real64_t gate_math_pow(gate_real64_t base, gate_real64_t exp)
553 {
554 2 return pow(base, exp);
555 }
556 21 gate_real64_t gate_math_sqrt(gate_real64_t value)
557 {
558 21 return sqrt(value);
559 }
560
561 7 gate_real64_t gate_math_ceil(gate_real64_t value)
562 {
563 7 return ceil(value);
564 }
565 13 gate_real64_t gate_math_floor(gate_real64_t value)
566 {
567 13 return floor(value);
568 }
569
570
571 #endif /* GATE_CORE_MATH_STD_IMPL */
572
573
574
575 #if defined(GATE_CORE_MATH_EFI_IMPL)
576
577 static gate_real64_t normalize_angle(gate_real64_t angle)
578 {
579 while (angle <= -GATE_MATH_CONST_PI)
580 {
581 angle += GATE_MATH_CONST_PI;
582 }
583 while (angle > GATE_MATH_CONST_PI)
584 {
585 angle -= GATE_MATH_CONST_PI;
586 }
587 return angle;
588 }
589
590 gate_real64_t gate_math_cos(gate_real64_t value)
591 {
592 static gate_real64_t const n2 = 2.0;
593 static gate_real64_t const n4 = 24.0;
594 static gate_real64_t const n6 = 720.0;
595 static gate_real64_t const n8 = 40320.0;
596 static gate_real64_t const n10 = 3628800.0;
597 static gate_real64_t const n12 = 479001600.0;
598 gate_real64_t const x = normalize_angle(value);
599 gate_real64_t const x2 = x * x;
600 gate_real64_t const x4 = x2 * x * x;
601 gate_real64_t const x6 = x4 * x * x;
602 gate_real64_t const x8 = x6 * x * x;
603 gate_real64_t const x10 = x8 * x * x;
604 gate_real64_t const x12 = x10 * x * x;
605
606 return 1 - x2 / n2 + x4 / n4 - x6 / n6 + x8 / n8 - x10 / n10 + x12 / n12;
607 }
608
609
610
611 gate_real64_t gate_math_sin(gate_real64_t value)
612 {
613 static gate_real64_t const n3 = 6.0;
614 static gate_real64_t const n5 = 120.0;
615 static gate_real64_t const n7 = 5040.0;
616 static gate_real64_t const n9 = 362880.0;
617 static gate_real64_t const n11 = 39916800.0;
618 static gate_real64_t const n13 = 6227020800.0;
619 gate_real64_t const x = normalize_angle(value);
620 gate_real64_t const x3 = x * x * x;
621 gate_real64_t const x5 = x3 * x * x;
622 gate_real64_t const x7 = x5 * x * x;
623 gate_real64_t const x9 = x7 * x * x;
624 gate_real64_t const x11 = x9 * x * x;
625 gate_real64_t const x13 = x11 * x * x;
626
627 return x - x3 / n3 + x5 / n5 - x7 / n7 + x9 / n9 - x11 / n11 + x13 / n13;
628 }
629 gate_real64_t gate_math_tan(gate_real64_t value)
630 {
631 return gate_math_sin(value) / gate_math_cos(value);
632 }
633
634 gate_real64_t gate_math_asin(gate_real64_t value)
635 {
636 /* https://de.wikipedia.org/wiki/Arkussinus_und_Arkuskosinus#Reihenentwicklungen */
637
638 static double const ret_0_96 = 1.2870022176;
639 /*static double const ret_1_00 = GATE_MATH_CONST_PI * 0.5;*/
640 static double const diff_1_00 = GATE_MATH_CONST_PI * 0.5 - 1.2870022176;
641 double ret = value;
642
643 if (value > 0.96)
644 {
645 /* iterative solution becomes unstable for value > 0.96
646 just apply a quick and dirty linear patch */
647 double factor = (value - 0.96) / (1.00 - 0.96);
648 ret = ret_0_96 + diff_1_00 * factor;
649 }
650 else
651 {
652 static unsigned const n_max = 107; /* quite OK up to 0.96 */
653 unsigned n;
654 double x = value;
655 double a = 1;
656 double b = 1;
657 for (n = 3; n != n_max; n += 2)
658 {
659 x *= value * value;
660 a *= ((double)n - 2.0);
661 b *= ((double)n - 1.0);
662 ret += a * x / (b * (double)n);
663 }
664 }
665
666 return ret;
667 }
668 gate_real64_t gate_math_acos(gate_real64_t value)
669 {
670 /* https://stackoverflow.com/questions/3380628/fast-arc-cos-algorithm/20914630 */
671 /* return (-0.69813170079773212 * value * value - 0.87266462599716477) * value + 1.5707963267948966; */
672 return GATE_MATH_CONST_PI * 0.5 - gate_math_asin(value);
673 }
674 gate_real64_t gate_math_atan(gate_real64_t value)
675 {
676 gate_real64_t ret;
677 ret = gate_math_asin(value / gate_math_sqrt(1 + value * value));
678 return ret;
679 }
680 gate_real64_t gate_math_atan2(gate_real64_t y, gate_real64_t x)
681 {
682 /* TODO */
683 return 0.0;
684 }
685 gate_real64_t gate_math_sinh(gate_real64_t value)
686 {
687 return 0.5 * (gate_math_exp(value) - gate_math_exp(-value));
688 }
689 gate_real64_t gate_math_cosh(gate_real64_t value)
690 {
691 return 0.5 * (gate_math_exp(value) + gate_math_exp(-value));
692 }
693 gate_real64_t gate_math_tanh(gate_real64_t value)
694 {
695 return gate_math_sinh(value) / gate_math_cosh(value);
696 }
697
698 gate_real64_t gate_math_exp(gate_real64_t value)
699 {
700 /* https://www.pseudorandom.com/implementing-exp */
701 gate_real64_t x0, tn;
702 gate_int64_t i, n;
703
704 if (gate_math_iszero(value))
705 {
706 return 1.0;
707 }
708 x0 = gate_math_abs_r64(value);
709 tn = 1.0;
710 n = 12;
711 n *= (gate_int64_t)gate_math_ceil(x0 * GATE_MATH_CONST_E);
712 for (i = n; i > 0; i--)
713 {
714 tn = tn * (x0 / i) + 1.0;
715 }
716
717 if (value < 0.0)
718 {
719 tn = 1.0 / tn;
720 }
721 return tn;
722 }
723 gate_real64_t gate_math_frexp(gate_real64_t value, int* exp)
724 {
725 /* TODO */
726 return 0.0;
727 }
728 gate_real64_t gate_math_ldexp(gate_real64_t value, int exp)
729 {
730 /* TODO */
731 return 0.0;
732 }
733
734 static unsigned msb(unsigned v)
735 {
736 unsigned ret = 0;
737 while (v >>= 1)
738 {
739 ret++;
740 }
741 return ret;
742 }
743
744 static float log_n(float value)
745 {
746 /* https://stackoverflow.com/questions/9799041/efficient-implementation-of-natural-logarithm-ln-and-exponentiation */
747 int log2;
748 float divisor, x, result;
749
750 log2 = msb((int)value); // See: https://stackoverflow.com/a/4970859/6630230
751 divisor = (float)(1 << log2);
752 x = value / divisor;
753 result = -1.7417939f + (2.8212026f + (-1.4699568f + (0.44717955f - 0.056570851f * x) * x) * x) * x;
754 result += ((float)log2) * 0.69314718f;
755
756 return result;
757 }
758
759
760 gate_real64_t gate_math_log(gate_real64_t value)
761 {
762 return (gate_real64_t)log_n((float)value);
763 }
764 gate_real64_t gate_math_log10(gate_real64_t value)
765 {
766 return gate_math_log(value) / gate_math_log(10.0);
767 }
768 gate_real64_t gate_math_modf(gate_real64_t value, gate_real64_t* intpart)
769 {
770 gate_real64_t ret;
771 gate_uint64_t ui;
772 if (value < 0.0)
773 {
774 ui = (gate_uint64_t)-value;
775 ret = -value - (gate_real64_t)ui;
776 if (intpart)
777 {
778 *intpart = -((gate_real64_t)ui);
779 }
780 }
781 else
782 {
783 ui = (gate_uint64_t)value;
784 ret = value - (gate_real64_t)ui;
785 if (intpart)
786 {
787 *intpart = (gate_real64_t)ui;
788 }
789 }
790 return ret;
791 }
792
793 gate_real64_t gate_math_pow(gate_real64_t base, gate_real64_t exp)
794 {
795 if (exp < 0.0)
796 {
797 return 1.0 / gate_math_pow_iexp(base, (gate_uint16_t)-exp);
798 }
799 else
800 {
801 return gate_math_pow_iexp(base, (gate_uint16_t)exp);
802 }
803 return 0.0;
804 }
805
806 union f_rsqrt_helper
807 {
808 float f;
809 gate_uint32_t i;
810 };
811
812
813 union d_rsqrt_helper
814 {
815 double d;
816 gate_uint64_t i;
817 };
818
819 /* https://en.wikipedia.org/wiki/Fast_inverse_square_root */
820 /* https://stackoverflow.com/questions/11644441/fast-inverse-square-root-on-x64/11644533 */
821 static float f_rsqrt(float number)
822 {
823 static const float threehalfs = 1.5F;
824 const float x2 = number * 0.5F;
825
826 union f_rsqrt_helper conv;
827 conv.f = number;
828 conv.i = 0x5f3759df - (conv.i >> 1);
829 conv.f *= threehalfs - (x2 * conv.f * conv.f);
830 return conv.f;
831 }
832
833 static double d_rsqrt(double number)
834 {
835 double y = number;
836 double x2 = y * 0.5;
837
838 union d_rsqrt_helper conv;
839 conv.d = y;
840 conv.i = 0x5fe6eb50c7b537a9 - (conv.i >> 1);
841 y = conv.d;
842 y = y * (1.5 - (x2 * y * y));
843 y = y * (1.5 - (x2 * y * y));
844 return y;
845 }
846
847
848 gate_real64_t gate_math_sqrt(gate_real64_t value)
849 {
850 double num = gate_math_abs_r64((double)value);
851 return (gate_real64_t)(1.0 / d_rsqrt(num));
852 }
853
854 gate_real64_t gate_math_ceil(gate_real64_t value)
855 {
856 gate_int64_t i = (gate_int64_t)value;
857 gate_real64_t diff = value - (gate_real64_t)i;
858 if (!gate_math_iszero(diff))
859 {
860 if (value >= 0.0)
861 {
862 i = (gate_int64_t)(value + 1.0);
863 }
864 else
865 {
866 i = -(gate_int64_t)(-value);
867 }
868 }
869 return (gate_real64_t)i;
870 }
871 gate_real64_t gate_math_floor(gate_real64_t value)
872 {
873 gate_int64_t i = (gate_int64_t)value;
874 gate_real64_t diff = value - (gate_real64_t)i;
875 if (!gate_math_iszero(diff))
876 {
877 if (value >= 0.0)
878 {
879 i = (gate_int64_t)(value);
880 }
881 else
882 {
883 i = -(gate_int64_t)(-value + 1.0);
884 }
885 }
886 return (gate_real64_t)i;
887 }
888
889 #endif /* GATE_CORE_MATH_EFI_IMPL */
890
891