FixMath
FixMath_Autotests.h
1 /*
2  * FixMath_Autotests.h
3  *
4  * Copyright 2024, Thomas Combriat, Thomas Friedrichsmeier and the Mozzi team
5  *
6  *
7  * FixMath is licensed under a GNU Lesser General Public Licence
8  *
9  */
10 
11 
14 namespace FixMathPrivate {
15  /* This function is never called, and has no effect, but simply encapsulates a bunch of static asserts */
16  inline void static_autotests() {
17  {
18  constexpr auto a = UFix<8,1>(64, true); // 32
19  constexpr auto b = UFix<8,2>(130, true); // 32.5
20  constexpr auto c = UFix<8,0>(33); // 33
21 
22  // basics
23  static_assert(a < b && b < c, "test fail");
24  static_assert(a.getNF() == 1 && b.getNF() == 2, "test fail");
25 
26  // addition
27  constexpr auto d = a + b;
28  static_assert(d.getNI() == 9, "test fail");
29  static_assert(d.getNF() == 2, "test fail"); // NF is always max in addition
30  static_assert((a + c).getNF() == 1, "test fail");
31  static_assert(d.asRaw() == 258, "test fail");
32  constexpr auto e = d + b + c; // addition of one 9 (NI) bit and two 8 (NI) bit numbers needs promotion to 10 bits, not 11, only.
33  static_assert(e.getNI() == 10, "test fail");
34  static_assert(e.getNF() == 2, "test fail");
35  e.assertSize<12>();
36  static_assert((d + d).getNI() == 10, "test fail");
37  static_assert((e + e).getNF() == 2, "test fail");
38  static_assert((d + e).getNI() == 11, "test fail");
39 
40  // Two's complement peculiar additions and opposite
41  static_assert(SFixAuto<-128>().getNI() == 7, "test fail");
42  static_assert(SFixAuto<127>().getNI() == 7, "test fail");
43  static_assert(SFixAuto<128>().getNI() == 8, "test fail");
44 
45 #if (__cplusplus >= 202002L)
46  constexpr auto s = SFix<7,0>(-128);
47  static_assert((s+s).getNI() == 8, "test fail");
48  static_assert((-s).getNI() == 8, "test fail");
49 
50  constexpr auto zero = SFix<7,0>(0);
51  constexpr auto negone = SFix<1,0>(-1);
52  static_assert((zero - s).getNI() == 8, "test fail");
53  static_assert(-(zero - s) == s, "test fail");
54  static_assert((s*negone).getNI() == 8, "test fail");
55 #endif
56  static_assert((-SFixAuto<-127>()).getNI() == 7, "test fail");
57  //static_assert((-SFixAuto<127>()).getNI() == 7, "test fail"); // if someone manages that I am very grateful
58  static_assert((-UFixAuto<127>()).getNI() == 7, "test fail");
59 
60 
61 
62  // the point of this block is to ascertain that addtion does not overflow, internally, where the internal_type of the operands is too small to hold the result
63  constexpr auto large = UFix<32,0>(1LL << 31, true);
64  static_assert(sizeof(decltype(large.asRaw())) == 4, "test fail");
65  static_assert((large+large).asRaw() == (1LL << 32), "test fail");
66  static_assert(sizeof(decltype((large+large).asRaw())) > 4, "test fail");
67 
68  // subtraction
69  static_assert(b - a == c - b, "test fail");
70  static_assert(c - UFix<17,8>(1) == a, "test fail");
71  static_assert(c - SFix<13,9>(1) == a, "test fail");
72  static_assert(b + a - b == a, "test fail");
73  static_assert(b + a + (-b) == a, "test fail"); // same with unary minus
74  static_assert(-(-a) == a, "test fail");
75 #if (__cplusplus >= 202002L)
76  // These here involve shifts of negative numbers, which used to be "implementation defined" before C++-20.
77  // It doesn't cause a real-world problem, but the compiler won't accept it in a constexpr
78  static_assert(UFix<43,9>(0) - b - a == -(a+b), "test fail");
79  static_assert(SFix<4, 3>(-1) == SFix<4, 5>(-1), "test fail"); // NOTE This is a simpler test case for the above problem. Note the difference in NF, which prompts shifting
80 #endif
81  // here's a variant that avoids the problem by using only positive numbers
82  static_assert(UFix<12,1>(999) - UFix<43,9>(0) - b - a == UFix<19,2>(999) + (-(a+b)), "test fail");
83  static_assert(-SFix<4, 3>(-8, true) == -SFix<4, 5>(-32, true), "test fail");
84 
85  // multiplication
86  static_assert(c * UFix<36, 5>(3ll << 31) == UFix<58,0>(33ll*(3ll << 31)), "test fail"); // NOTE: The exact values are aribrary, but we want something that would overflow the initial type range
87  static_assert(a * UFix<0, 2>(3, true) == UFix<17, 8>(24), "test fail"); // 32 * .75 == 24
88  static_assert(a * UFix<5, 0>(4).invAccurate() == UFix<17, 8>(8), "test fail"); // 32 * (1/4) == 8
89  static_assert(a * toUFraction((int8_t) 16) == UFix<3, 9>(2), "test fail"); // 32 * (16/256) == 2
90 
91  // type conversions
92  static_assert(a.getNI() == a.asSFix().getNI(), "test fail");
93  static_assert(a.getNF() == a.asSFix().getNF(), "test fail");
94 
95  // UFixAuto() / SFixAuto()
96  static_assert(FixMathPrivate::NIcount<0>() == 0, "test fail");
97  static_assert(FixMathPrivate::NIcount<1>() == 1, "test fail");
98  static_assert(FixMathPrivate::NIcount<2>() == 2, "test fail");
99  static_assert(FixMathPrivate::NIcount<3>() == 2, "test fail");
100  static_assert(FixMathPrivate::NIcount<4>() == 3, "test fail");
101 
102  UFixAuto<3>().assertSize<2>();
103  UFixAuto<3>().sR<2>().assertSize<2>();
104  // TODO: This one could be optimized, further!
105  SFixAuto<16>().assertSize<6>();
106  }
107  }
108 }
109 
110 
constexpr UFix< 0, sizeof(T) *8 > toUFraction(T val)
Definition: FixMath.h:703
Definition: FixMath.h:754
Definition: FixMath.h:170
Definition: FixMath.h:126