1 /*
2
3 Copyright (C) 2015-2018 Night Dive Studios, LLC.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 */
19 /*
20 * $Header: r:/prj/lib/src/fixpp/RCS/fixpp.h 1.45 1994/08/08 18:27:45 ept Exp $
21 */
22
23 /*
24 I'd like to dedicate this fixpoint library to Dan and Matt for their
25 inspirational bravery, and to C++ for being such a complex and neurotic
26 language.
27 */
28
29 #ifndef __FIXPP_H
30 #define __FIXPP_H
31
32 #include <istream>
33 #include <cstdio>
34 #include <cstdlib>
35
36 extern "C" {
37 //#include "mprintf.h"
38 #include "fix.h" // A big thank you to Dan and Matt.
39 }
40
41 // How many bits to shift an integer up to make it a fixpoint.
42 // ===========================================================
43 #ifdef FIXPOINT_SHIFTUP
44 #define SHIFTUP FIXPOINT_SHIFTUP
45 #else
46 #define SHIFTUP 16 // 16:16 default format.
47 #endif
48
49 #define SHIFTMULTIPLIER (1 << SHIFTUP)
50
51 // Here are some flags for your convenience.
52 // =========================================
53
54 // Define this for some misc. debugging things like touch()
55 // ========================================================
56 //#define FIXDEBUG
57
58 #ifdef FIXDEBUG
59 #define CLICK(c) c += (Fixpoint::click_bool)
60 #else
61 #define CLICK(c)
62 #endif
63
64 // Here is a nice forward declaration.
65 // ===================================
66
67 class Fixpoint;
68
69 #define Q Fixpoint
70
71 class Fixpoint {
72
73 friend Fixpoint rawConstruct(int32_t l);
74
75 public:
76 // The data is stored here.
77 // ========================
78 int32_t val;
79
80 // Some invasive functions to get right at the internal rep.
81 // What? Me not secure? I'm no fascist.
82 // =========================================================
83
84 uint32_t bits();
85 void setbits(uint32_t ul);
86
87 // Constructors.
88 // =============
89
90 Fixpoint();
91
92 Fixpoint(const Fixpoint &);
93
94 Fixpoint(int32_t i);
95
96 Fixpoint(uint32_t i);
97
98 Fixpoint(double);
99
100 // Conversions.
101 // ============
102
103 double to_double() const;
104
105 float to_float() const;
106
107 int32_t to_int() const;
108
109 fix to_fix() const;
110
111 fixang to_fixang() const;
112
113 // Reverse Conversions.
114 // ====================
115
116 void fix_to(fix);
117
118 void fixang_to(fixang);
119
120 // Assignments.
121 // ============
122
123 // REMOVED!!!!
124
125 // Arithmetic operators (homogeneous)!!
126 // ====================================
127
128 Fixpoint &operator+=(Fixpoint);
129
130 Fixpoint &operator-=(Fixpoint);
131
132 Fixpoint &operator*=(Fixpoint);
133
134 Fixpoint &operator/=(Fixpoint);
135
136 Fixpoint &operator<<=(uint32_t n);
137
138 Fixpoint &operator>>=(uint32_t n);
139
140 Fixpoint operator-() const;
141
142 Fixpoint operator+() const;
143
144 int32_t operator<(const Fixpoint &) const;
145
146 int32_t operator>(const Fixpoint &) const;
147
148 int32_t operator<=(const Fixpoint &fp2) const;
149
150 int32_t operator>=(const Fixpoint &fp2) const;
151
152 int32_t operator==(const Fixpoint &fp2) const;
153
154 int32_t operator!=(const Fixpoint &fp2) const;
155
156 // Signed shifts
157 // =============
158
159 void shift(int32_t n);
160 Fixpoint shifted(int32_t n) const;
161
162 // Fast comparisons with zero (maybe... perhaps Q(0) isn't so slow after all)
163 // (and a trip down memory lane for FORTRAN-ites)
164 // ====================================
165
166 int32_t gt_zero() const;
167
168 int32_t ge_zero() const;
169
170 int32_t eq_zero() const;
171
172 int32_t ne_zero() const;
173
174 int32_t le_zero() const;
175
176 int32_t lt_zero() const;
177
178 // Friendly math function declarations.
179 // ====================================
180
181 friend inline Fixpoint sqrt(Fixpoint);
182 friend inline Fixpoint exp(Fixpoint);
183 friend inline int32_t floor(Fixpoint);
184 friend inline Fixpoint sin(Fixpoint);
185 friend inline Fixpoint cos(Fixpoint);
186 friend inline Fixpoint tan(Fixpoint);
187 friend inline Fixpoint acos(Fixpoint);
188 friend inline Fixpoint asin(Fixpoint);
189 friend inline void sincos(Fixpoint ang, Fixpoint *sn, Fixpoint *cs);
190 friend inline Fixpoint atan2(Fixpoint, Fixpoint);
191 friend inline Fixpoint fsin(Fixpoint);
192 friend inline Fixpoint fcos(Fixpoint);
193 friend inline void fsincos(Fixpoint ang, Fixpoint *sn, Fixpoint *cs);
194 friend inline Fixpoint abs(Fixpoint);
195
196 #ifdef FIXDEBUG
197
198 friend char *bitdump(Fixpoint &);
199
200 // Reporting.
201 // ==========
202
203 static uint8_t click_bool;
204
205 static uint32_t constructor_void, constructor_Fixpoint, constructor_int, constructor_uint, constructor_lint,
206 constructor_ulint, constructor_double;
207
208 static uint32_t ass_Fixpoint, ass_int, ass_uint, ass_lint, ass_ulint, ass_double;
209
210 static uint32_t binary_add, binary_sub, binary_mul, binary_div;
211
212 static uint32_t add_eq, sub_eq, mul_eq, div_eq;
213
214 static uint32_t unary_minus, unary_plus;
215
216 static uint32_t cond_l, cond_g, cond_le, cond_ge, cond_eq, cond_neq;
217
report_on(void)218 static void report_on(void) { click_bool = 1; }
report_off(void)219 static void report_off(void) { click_bool = 0; }
220
221 static void report(std::ostream &);
222 static void report(void);
223 static void reset_report(void);
224
225 #endif /* FIXDEBUG */
226
227 } /* Blessed be!! */;
228
229 // Constructors
230 // ============
231
bits()232 inline uint32_t Fixpoint::bits() { return (uint32_t)val; }
setbits(uint32_t ul)233 inline void Fixpoint::setbits(uint32_t ul) { val = ul; }
234
Fixpoint()235 inline Fixpoint::Fixpoint() { CLICK(constructor_void); } // Hey, why not define our own....
236
Fixpoint(const Fixpoint & fp)237 inline Fixpoint::Fixpoint(const Fixpoint &fp) {
238 CLICK(constructor_Fixpoint);
239 val = fp.val;
240 }
241
Fixpoint(int32_t i)242 inline Fixpoint::Fixpoint(int32_t i) {
243 CLICK(constructor_int);
244 val = i << SHIFTUP;
245 }
246
Fixpoint(uint32_t i)247 inline Fixpoint::Fixpoint(uint32_t i) {
248 CLICK(constructor_uint);
249 val = i << SHIFTUP;
250 }
251
Fixpoint(double d)252 inline Fixpoint::Fixpoint(double d) {
253 CLICK(constructor_double);
254 val = (int32_t)(d * SHIFTMULTIPLIER);
255 }
256
rawConstruct(int32_t l)257 inline Fixpoint rawConstruct(int32_t l) {
258 Fixpoint f;
259 f.val = l;
260 return f;
261 }
262 #define f2Fixpoint(x) (rawConstruct((int32_t)((x)*SHIFTMULTIPLIER)))
263
264 // ======================================
265 //
266 // Math functions.
267 //
268 // ======================================
269
270 ////////////
271 // //
272 // += //
273 // //
274 ////////////
275 inline Fixpoint &Fixpoint::operator+=(Fixpoint fp2) {
276 CLICK(add_eq);
277
278 val += fp2.val;
279
280 return *this;
281 }
282
283 ////////////
284 // //
285 // -= //
286 // //
287 ////////////
288 inline Fixpoint &Fixpoint::operator-=(Fixpoint fp2) {
289 CLICK(sub_eq);
290
291 val -= fp2.val;
292 return *this;
293 }
294
295 ////////////
296 // //
297 // *= //
298 // //
299 ////////////
300 inline Fixpoint &Fixpoint::operator*=(Fixpoint fp2) {
301 CLICK(mul_eq);
302
303 val = (int32_t)fix_mul((fix)val, (fix)fp2.val);
304 return *this;
305 }
306
307 ////////////
308 // //
309 // /= //
310 // //
311 ////////////
312 inline Fixpoint &Fixpoint::operator/=(Fixpoint fp2) {
313 CLICK(div_eq);
314
315 val = (int32_t)fix_div((fix)val, (fix)fp2.val);
316 // val = _fix_do_div(val, fp2.val);
317 return *this;
318 }
319
320 inline Fixpoint &Fixpoint::operator<<=(uint32_t n) {
321 val <<= n;
322 return *this;
323 }
324
325 inline Fixpoint &Fixpoint::operator>>=(uint32_t n) {
326 val >>= n;
327 return *this;
328 }
329
330 inline Fixpoint operator+(Fixpoint a, Fixpoint b) {
331 CLICK(Fixpoint::binary_add);
332 a.val += b.val;
333 return a;
334 }
335
336 inline Fixpoint operator-(Fixpoint a, Fixpoint b) {
337 CLICK(Fixpoint::binary_sub);
338 a.val -= b.val;
339 return a;
340 }
341
342 inline Fixpoint operator*(Fixpoint a, Fixpoint b) {
343 CLICK(Fixpoint::binary_mul);
344 a.val = (int32_t)fix_mul((fix)a.val, (fix)b.val);
345 return a;
346 }
347
348 inline Fixpoint operator/(Fixpoint a, Fixpoint b) {
349 CLICK(Fixpoint::binary_div);
350 a.val = (int32_t)fix_div((fix)a.val, (fix)b.val);
351 // a.val=_fix_do_div(a.val,b.val);
352 return a;
353 }
354
355 ///////////
356 // //
357 // - //
358 // //
359 ///////////
360 inline Fixpoint Fixpoint::operator-() const {
361 Fixpoint ans;
362
363 CLICK(unary_minus);
364
365 ans.val = -this->val;
366
367 return ans;
368 }
369
370 ///////////
371 // //
372 // + //
373 // //
374 ///////////
375 inline Fixpoint Fixpoint::operator+() const {
376 CLICK(unary_plus);
377
378 return *this;
379 }
380
shift(int32_t n)381 inline void Fixpoint::shift(int32_t n) {
382 if (n > 0)
383 val <<= n;
384 else if (n < 0)
385 val >>= (-n);
386 }
387
shifted(int32_t n)388 inline Fixpoint Fixpoint::shifted(int32_t n) const {
389 Fixpoint r(*this);
390 if (n > 0)
391 r.val <<= n;
392 else if (n < 0)
393 r.val >>= (-n);
394 return r;
395 }
396
397 inline Fixpoint operator<<(Fixpoint p, unsigned int n) {
398 p.val <<= n;
399 return p;
400 }
401
402 inline Fixpoint operator>>(Fixpoint p, unsigned int n) {
403 p.val >>= n;
404 return p;
405 }
406
407 // Conversions.
408 // ============
409
to_double()410 inline double Fixpoint::to_double() const { return ((double)val) / SHIFTMULTIPLIER; }
411
to_float()412 inline float Fixpoint::to_float() const { return ((float)val) / SHIFTMULTIPLIER; }
413
to_int()414 inline int32_t Fixpoint::to_int() const { return (int32_t)(val >> SHIFTUP); }
415
to_fix()416 inline fix Fixpoint::to_fix() const { return (fix)val; }
417
to_fixang()418 inline fixang Fixpoint::to_fixang() const {
419 Fixpoint temp = *this * f2Fixpoint(0.159154943);
420
421 // for temp, 360 degrees = 1.0.
422 // The lower 16 bits of the internal rep is the fixang.
423
424 return (uint16_t)temp.val;
425 }
426
fix_to(fix f)427 inline void Fixpoint::fix_to(fix f) { val = f; }
428
fixang_to(fixang f)429 inline void Fixpoint::fixang_to(fixang f) {
430 val = ((int32_t)(int16_t)(f - 1)) + 1;
431 *this *= f2Fixpoint(6.283185306);
432 }
433
434 // Comparisons.
435 // ============
436
437 ///////////
438 // //
439 // < //
440 // //
441 ///////////
442 inline int32_t Fixpoint::operator<(const Fixpoint &fp2) const {
443 CLICK(cond_l);
444
445 return this->val < fp2.val;
446 }
447
448 ///////////
449 // //
450 // > //
451 // //
452 ///////////
453 inline int32_t Fixpoint::operator>(const Fixpoint &fp2) const {
454 CLICK(cond_g);
455
456 return this->val > fp2.val;
457 }
458
459 ////////////
460 // //
461 // <= //
462 // //
463 ////////////
464 inline int32_t Fixpoint::operator<=(const Fixpoint &fp2) const {
465 CLICK(cond_le);
466
467 return this->val <= fp2.val;
468 }
469
470 ////////////
471 // //
472 // >= //
473 // //
474 ////////////
475 inline int32_t Fixpoint::operator>=(const Fixpoint &fp2) const {
476 CLICK(cond_ge);
477
478 return this->val >= fp2.val;
479 }
480
481 ////////////
482 // //
483 // == //
484 // //
485 ////////////
486 inline int32_t Fixpoint::operator==(const Fixpoint &fp2) const {
487 CLICK(cond_eq);
488
489 return this->val == fp2.val;
490 }
491
492 ////////////
493 // //
494 // != //
495 // //
496 ////////////
497 inline int32_t Fixpoint::operator!=(const Fixpoint &fp2) const {
498 CLICK(cond_neq);
499
500 return this->val != fp2.val;
501 }
502
503 // ======================================
504 //
505 // Comparisons with zero
506 //
507 // ======================================
508
gt_zero()509 inline int32_t Fixpoint::gt_zero() const { return (val > 0); }
510
ge_zero()511 inline int32_t Fixpoint::ge_zero() const { return (val >= 0); }
512
eq_zero()513 inline int32_t Fixpoint::eq_zero() const { return (val == 0); }
514
ne_zero()515 inline int32_t Fixpoint::ne_zero() const { return (val != 0); }
516
le_zero()517 inline int32_t Fixpoint::le_zero() const { return (val <= 0); }
518
lt_zero()519 inline int32_t Fixpoint::lt_zero() const { return (val < 0); }
520
521 // ======================================
522 //
523 // Mixed math.
524 //
525 // ======================================
526
527 inline Fixpoint operator*(int32_t i, Fixpoint const &fp) { return Fixpoint(i) * fp; }
528 inline Fixpoint operator*(uint32_t i, Fixpoint const &fp) { return Fixpoint(i) * fp; }
529 inline Fixpoint operator*(double d, Fixpoint const &fp) { return Fixpoint(d) * fp; }
530
531 inline Fixpoint operator-(int32_t i, Fixpoint const &fp) { return Fixpoint(i) - fp; }
532 inline Fixpoint operator-(uint32_t i, Fixpoint const &fp) { return Fixpoint(i) - fp; }
533 inline Fixpoint operator-(double d, Fixpoint const &fp) { return Fixpoint(d) - fp; }
534
535 inline Fixpoint operator+(int32_t i, Fixpoint const &fp) { return Fixpoint(i) + fp; }
536 inline Fixpoint operator+(uint32_t i, Fixpoint const &fp) { return Fixpoint(i) + fp; }
537 inline Fixpoint operator+(double d, Fixpoint const &fp) { return Fixpoint(d) + fp; }
538
539 inline Fixpoint operator/(int32_t i, Fixpoint const &fp) { return Fixpoint(i) / fp; }
540 inline Fixpoint operator/(uint32_t i, Fixpoint const &fp) { return Fixpoint(i) / fp; }
541 inline Fixpoint operator/(double d, Fixpoint const &fp) { return Fixpoint(d) / fp; }
542
543 #ifdef BADMIX
544
545 inline Fixpoint operator*=(int32_t i, Fixpoint fp) { return Fixpoint(i) *= fp; }
546 inline Fixpoint operator*=(uint32_t i, Fixpoint fp) { return Fixpoint(i) *= fp; }
547 inline Fixpoint operator*=(double d, Fixpoint fp) { return Fixpoint(d) *= fp; }
548
549 #endif
550
551 // ======================================
552 //
553 // I/O functions.
554 //
555 // ======================================
556
557 // ======================================
558 //
559 // I/O functions.
560 //
561 // ======================================
562
563 inline std::ostream &operator<<(std::ostream &os, const Fixpoint &fp) {
564 os << fp.to_double();
565
566 return os;
567 }
568
569 inline std::istream &operator>>(std::istream &is, Fixpoint &fp) {
570 double temp;
571
572 is >> temp;
573
574 fp = temp;
575
576 return is;
577 }
578
579 // ====================================================
580 //
581 // Math functions.
582 //
583 // ====================================================
584
mul_div(Fixpoint a,Fixpoint b,Fixpoint c)585 inline Fixpoint mul_div(Fixpoint a, Fixpoint b, Fixpoint c) {
586 Fixpoint r;
587 r.val = (int32_t)fix_mul_div((fix)a.val, (fix)b.val, (fix)c.val);
588 return r;
589 }
590
sqrt(Fixpoint a)591 inline Fixpoint sqrt(Fixpoint a) {
592 Fixpoint ans;
593
594 ans.val = fix_sqrt(a.val);
595
596 return ans;
597 }
598
exp(Fixpoint a)599 inline Fixpoint exp(Fixpoint a) {
600 Fixpoint ans;
601 ans.val = fix_exp(a.val);
602 return ans;
603 }
604
floor(Fixpoint a)605 inline int32_t floor(Fixpoint a) { return a.val >> SHIFTUP; }
606
sin(Fixpoint a)607 inline Fixpoint sin(Fixpoint a) {
608 Fixpoint ans;
609
610 ans.val = fix_sin(a.to_fixang());
611
612 return ans;
613 }
614
cos(Fixpoint a)615 inline Fixpoint cos(Fixpoint a) {
616 Fixpoint ans;
617
618 ans.val = fix_cos(a.to_fixang());
619
620 return ans;
621 }
622
tan(Fixpoint a)623 inline Fixpoint tan(Fixpoint a) {
624 Fixpoint sn, cs;
625
626 sn = sin(a);
627 cs = cos(a);
628 if (cs == 0)
629 return 0;
630 else
631 return sn / cs;
632 }
633
asin(Fixpoint a)634 inline Fixpoint asin(Fixpoint a) {
635 Fixpoint ans;
636
637 ans.fixang_to(fix_asin(a.to_fix()));
638
639 return ans;
640 }
641
acos(Fixpoint a)642 inline Fixpoint acos(Fixpoint a) {
643 Fixpoint ans;
644
645 ans.fixang_to(fix_acos(a.to_fix()));
646
647 return ans;
648 }
649
sincos(Fixpoint ang,Fixpoint * sn,Fixpoint * cs)650 inline void sincos(Fixpoint ang, Fixpoint *sn, Fixpoint *cs) {
651 fix fsn, fcs;
652 fix_sincos(ang.to_fixang(), &fsn, &fcs);
653 sn->val = fsn;
654 cs->val = fcs;
655 }
656
atan2(Fixpoint y,Fixpoint x)657 inline Fixpoint atan2(Fixpoint y, Fixpoint x) {
658 Fixpoint ans;
659
660 ans.fixang_to(fix_atan2(y.to_fix(), x.to_fix()));
661
662 return ans;
663 }
664
fsin(Fixpoint a)665 inline Fixpoint fsin(Fixpoint a) {
666 Fixpoint ans;
667
668 ans.val = fix_fastsin(a.to_fixang());
669
670 return ans;
671 }
672
fcos(Fixpoint a)673 inline Fixpoint fcos(Fixpoint a) {
674 Fixpoint ans;
675
676 ans.val = fix_fastcos(a.to_fixang());
677
678 return ans;
679 }
680
fsincos(Fixpoint ang,Fixpoint * sn,Fixpoint * cs)681 inline void fsincos(Fixpoint ang, Fixpoint *sn, Fixpoint *cs) {
682 fix fsn, fcs;
683 fix_fastsincos(ang.to_fixang(), &fsn, &fcs);
684 sn->val = fsn;
685 cs->val = fcs;
686 }
687
abs(Fixpoint fp)688 inline Fixpoint abs(Fixpoint fp) {
689 Fixpoint ans;
690
691 ans.val = labs(fp.val);
692
693 return ans;
694 }
695
696 #ifdef FIXDEBUG
697
698 void touch(Fixpoint &);
699
700 #endif /* FIXDEBUG */
701
702 #endif /* !__FIXPP_H */
703