Skip to content

Commit 2e891aa

Browse files
authored
Merge pull request #12 from tomcombriat/work/fix_from_const
Better construction of UFix from compile time constants
2 parents 947351e + 1efcc72 commit 2e891aa

2 files changed

Lines changed: 105 additions & 38 deletions

File tree

src/FixMath.h

Lines changed: 93 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,6 @@ The division is not implemented. This is a deliberate choice made for two reason
120120

121121

122122

123-
124123
/** constexpr functions used internally.
125124
*/
126125

@@ -134,6 +133,16 @@ namespace FixMathPrivate {
134133
constexpr uint64_t uFullRange(int8_t N) { return ((uint64_t(1)<<(N-1))-1) + (uint64_t(1)<<(N-1));}
135134
constexpr uint64_t rangeAdd(byte NF, byte _NF, uint64_t RANGE, uint64_t _RANGE) { return ((NF > _NF) ? (RANGE + (_RANGE<<(NF-_NF))) : (_RANGE + (RANGE<<(_NF-NF))));} // returns the RANGE following an addition
136135
constexpr uint64_t rangeShift(int8_t N, int8_t SH, uint64_t RANGE) { return ((SH < N) ? (RANGE) : (shiftR(RANGE,(N-SH))));} // make sure that NI or NF does not turn negative when safe shifts are used.
136+
137+
// Helper struct for NIcount(), below. Needed, because C++ does not allow partial specialization of functions
138+
template<uint64_t value, int8_t bits> struct BitCounter {
139+
static constexpr int8_t bitsNeeded() { return (value >= (uint64_t(1) << bits) ? bits+1 : (BitCounter<value, bits-1>::bitsNeeded())); }
140+
};
141+
template<uint64_t value> struct BitCounter<value, 0> {
142+
static constexpr int8_t bitsNeeded() { return (value < 1 ? 0 : 1); }
143+
};
144+
// Count number of bits needed to represent the constant value (up to 64 bits). Value is specified as template parameter to constrict usage to compile-time evaluation.
145+
template<uint64_t value> constexpr int8_t NIcount() { return BitCounter<value, 63>::bitsNeeded(); };
137146
}
138147

139148
// Forward declaration
@@ -144,7 +153,12 @@ class SFix;
144153
template<int8_t NI, int8_t NF, uint64_t RANGE=FixMathPrivate::uFullRange(NI+NF)>
145154
class UFix;
146155

147-
156+
namespace FixMathPrivate {
157+
// Alias declaration for a UFix type with the suitable NI count given RANGE and NF
158+
template<int8_t NF, uint64_t RANGE> using UFixByRange_t=UFix<NIcount<RANGE>()-NF, NF, RANGE>;
159+
// Alias declaration for an SFix type with the suitable NI count given RANGE and NF
160+
template<int8_t NF, uint64_t RANGE> using SFixByRange_t=SFix<NIcount<RANGE>()-NF, NF, RANGE>;
161+
}
148162

149163
/** Instanciate an unsigned fixed point math number.
150164
@param NI The number of bits encoding the integer part. The integral part can range into [0, 2^NI -1]
@@ -222,11 +236,10 @@ class UFix
222236
@return The result of the addition as a UFix.
223237
*/
224238
template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
225-
constexpr typename UFix<FixMathPrivate::FM_max(NI,_NI), FixMathPrivate::FM_max(NF,_NF), FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)>::UFixNIadj_t operator+ (const UFix<_NI,_NF,_RANGE>& op) const // NOTE: C++-11 does not (yet) allow auto return value
239+
constexpr FixMathPrivate::UFixByRange_t<FixMathPrivate::FM_max(NF,_NF), FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)> operator+ (const UFix<_NI,_NF,_RANGE>& op) const // NOTE: C++-11 does not (yet) allow auto return value
226240
{
227-
using namespace FixMathPrivate;
228-
typedef UFix<FM_max(NI,_NI), FM_max(NF,_NF), rangeAdd(NF,_NF,RANGE,_RANGE)> temptype; // intermediate type with the correct RANGE, but not necessarily the required NI
229-
typedef typename temptype::UFixNIadj_t worktype; // the proper return type, with NI adjusted according the range calculated, above
241+
// Number of NI in return type amy be FM_max(NI, _NI), or FM_max(NI, _NI)+1. Most easily determined from the resulting RANGE
242+
typedef FixMathPrivate::UFixByRange_t<FixMathPrivate::FM_max(NF,_NF), FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)> worktype;
230243

231244
return worktype(worktype(*this).asRaw() + worktype(op).asRaw(), true);
232245
}
@@ -236,11 +249,9 @@ class UFix
236249
@return The result of the addition as a SFix.
237250
*/
238251
template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
239-
constexpr typename SFix<FixMathPrivate::FM_max(NI,_NI), FixMathPrivate::FM_max(NF,_NF), FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)>::SFixNIadj_t operator+ (const SFix<_NI,_NF,_RANGE>& op) const
252+
constexpr FixMathPrivate::SFixByRange_t<FixMathPrivate::FM_max(NF,_NF), FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)> operator+ (const SFix<_NI,_NF,_RANGE>& op) const
240253
{
241-
using namespace FixMathPrivate;
242-
typedef SFix<FM_max(NI,_NI), FM_max(NF,_NF), rangeAdd(NF,_NF,RANGE,_RANGE)> temptype;
243-
typedef typename temptype::SFixNIadj_t worktype;
254+
typedef FixMathPrivate::SFixByRange_t<FixMathPrivate::FM_max(NF,_NF), FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)> worktype;
244255

245256
return worktype(worktype(*this).asRaw() + worktype(op).asRaw(), true);
246257
}
@@ -265,10 +276,10 @@ class UFix
265276
@return The result of the subtraction as a SFix.
266277
*/
267278
template<int8_t _NI, int8_t _NF, uint64_t _RANGE> // We do not have the +1 after FixMathPrivate::FM_max(NI, _NI) because the substraction between two UFix should fit in the biggest of the two.
268-
constexpr SFix<FixMathPrivate::FM_max(NI,_NI),FixMathPrivate::FM_max(NF,_NF), FixMathPrivate::FM_max(FixMathPrivate::shiftR(RANGE,FixMathPrivate::FM_max(NF,_NF)-NF), FixMathPrivate::shiftR(_RANGE,FixMathPrivate::FM_max(NF,_NF)-_NF))> operator- (const UFix<_NI,_NF, _RANGE>& op) const
279+
constexpr FixMathPrivate::SFixByRange_t<FixMathPrivate::FM_max(NF,_NF), FixMathPrivate::FM_max(FixMathPrivate::shiftR(RANGE,FixMathPrivate::FM_max(NF,_NF)-NF), FixMathPrivate::shiftR(_RANGE,FixMathPrivate::FM_max(NF,_NF)-_NF))> operator- (const UFix<_NI,_NF, _RANGE>& op) const
269280
{
270281
using namespace FixMathPrivate;
271-
typedef SFix<FM_max(NI,_NI),FM_max(NF,_NF), FM_max(shiftR(RANGE,FM_max(NF,_NF)-NF), shiftR(_RANGE,FM_max(NF,_NF)-_NF))> worktype;
282+
typedef SFixByRange_t<FM_max(NF,_NF), FM_max(shiftR(RANGE,FM_max(NF,_NF)-NF), shiftR(_RANGE,FM_max(NF,_NF)-_NF))> worktype;
272283

273284
return worktype(worktype(*this).asRaw() - worktype(op).asRaw(), true);
274285
}
@@ -279,7 +290,7 @@ class UFix
279290
@return The result of the subtraction of op1 by op2. As a SFix
280291
*/
281292
template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
282-
constexpr typename SFix<FixMathPrivate::FM_max(NI,_NI),FixMathPrivate::FM_max(NF,_NF),FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)>::SFixNIadj_t operator- (const SFix<_NI,_NF, _RANGE>& op2) const
293+
constexpr FixMathPrivate::SFixByRange_t<FixMathPrivate::FM_max(NF,_NF), FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)> operator- (const SFix<_NI,_NF, _RANGE>& op2) const
283294
{
284295
return -op2+(*this);
285296
}
@@ -312,9 +323,9 @@ class UFix
312323
@return The result of the multiplication as a UFix.
313324
*/
314325
template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
315-
constexpr typename UFix<NI+_NI, NF+_NF, RANGE*_RANGE>::UFixNIadj_t operator* (const UFix<_NI,_NF,_RANGE>& op) const
326+
constexpr FixMathPrivate::UFixByRange_t<NF+_NF, RANGE*_RANGE> operator* (const UFix<_NI,_NF,_RANGE>& op) const
316327
{
317-
typedef typename UFix<NI+_NI, NF+_NF, RANGE*_RANGE>::UFixNIadj_t worktype;
328+
typedef FixMathPrivate::UFixByRange_t<NF+_NF, RANGE*_RANGE> worktype;
318329
return worktype((typename worktype::internal_type) (internal_value)*op.asRaw(), true);
319330
}
320331

@@ -323,9 +334,9 @@ class UFix
323334
@return The result of the multiplication as a SFix.
324335
*/
325336
template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
326-
constexpr typename SFix<NI+_NI, NF+_NF, RANGE*_RANGE>::SFixNIadj_t operator* (const SFix<_NI,_NF,_RANGE>& op) const
337+
constexpr FixMathPrivate::SFixByRange_t<NF+_NF, RANGE*_RANGE> operator* (const SFix<_NI,_NF,_RANGE>& op) const
327338
{
328-
typedef typename SFix<NI+_NI, NF+_NF, RANGE*_RANGE>::SFixNIadj_t worktype;
339+
typedef FixMathPrivate::SFixByRange_t<NF+_NF, RANGE*_RANGE> worktype;
329340
return worktype((typename worktype::internal_type) (internal_value)*op.asRaw(), true);
330341
}
331342

@@ -561,10 +572,8 @@ class UFix
561572
*/
562573
template<int8_t BITS> static constexpr void assertSize() { static_assert(NI+NF <= BITS, "Data type is larger than expected!"); }
563574
private:
564-
template<int8_t, int8_t, uint64_t> friend class UFix; // All sibling specializations shall be friends, too
575+
template<int8_t, int8_t, uint64_t> friend class UFix; // for access to internal_type
565576
template<int8_t, int8_t, uint64_t> friend class SFix;
566-
static constexpr uint64_t maxRANGE(int8_t delta_bits=0) { return ((uint64_t(1)<<(NI+NF+delta_bits-1)) - 1 + (uint64_t(1)<<(NI+NF+delta_bits-1))); } // == 1 << NI+NF+delta_bits, but not overflowing at NIF+NF+delta_bits==64
567-
typedef UFix<(RANGE > maxRANGE()) ? NI+1 : (RANGE > maxRANGE(-1)) ? NI : NI-1, NF, RANGE> UFixNIadj_t;
568577

569578
internal_type internal_value;
570579
//static constexpr internal_type onesbitmask() { return (internal_type) ((1ULL<< (NI+NF)) - 1); }
@@ -678,6 +687,10 @@ constexpr SFix<NI, NF> operator-(double op, const UFix<NI, NF>& uf) {return -uf+
678687
whereas the latter will lead to NF=8. Mozzi's objects (Oscil and the like)
679688
returns correct types, hence you can use this function to convert the return
680689
value of a Mozzi's function/class member into a pure fractional number.
690+
691+
@note If the value is known at compile time, it is much more efficient to
692+
construct using UFixAuto(), and then shifting to the right.
693+
681694
@param val The value to be converted into a pure fractional number.
682695
@return A UFix<0,NF> with NF chosen according to the input type
683696
*/
@@ -693,6 +706,10 @@ constexpr inline UFix<0, sizeof(T)*8> toUFraction(T val) {
693706
whereas the latter will lead to NI=8. Mozzi's objects (Oscil and the like)
694707
returns correct types, hence you can use this function to convert the return
695708
value of a Mozzi's function/class member into a pure fractional number.
709+
710+
@note If the value is known at compile time, it is much more efficient to
711+
construct using UFixAuto().
712+
696713
@param val The value to be converted into a pure unsigned integer fixed math number.
697714
@return A UFix<NI,0> with NI chosen according to the input type
698715
*/
@@ -701,6 +718,24 @@ constexpr inline UFix<sizeof(T)*8,0> toUInt(T val) {
701718
return UFix<sizeof(T)*8,0>::fromRaw(val);
702719
}
703720

721+
/** Create a pure integer unsigned fix number (UFix) from a compile time constant.
722+
The number of integer bits needed is determined, automatically, based on the actual
723+
value. This allows to easily create constants requiring minimal storage, without
724+
counting bits, manually.
725+
726+
Examples:
727+
@code
728+
auto three = UFixAuto<3>(); // UFix<2, 0>
729+
auto ten_point_five = UFixAuto<21>().sR<1>(); // UFix<5, 1>
730+
auto nearly_Pi = UFixAuto<201>().sR<6>(); // UFix<2, 6> = 3.140625
731+
@endcode
732+
*/
733+
// TODO: auto sixteen = UFixAuto<16>(); could be made to return UFix<1, -4>!
734+
template<uint64_t value>
735+
constexpr FixMathPrivate::UFixByRange_t<0, value> UFixAuto() {
736+
return FixMathPrivate::UFixByRange_t<0, value>::fromRaw(value);
737+
}
738+
704739

705740

706741
/** Instanciate an signed fixed point math number.
@@ -772,10 +807,9 @@ class SFix
772807
@return The result of the addition as a SFix.
773808
*/
774809
template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
775-
constexpr typename SFix<FixMathPrivate::FM_max(NI,_NI),FixMathPrivate::FM_max(NF,_NF),FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)>::SFixNIadj_t operator+ (const SFix<_NI,_NF,_RANGE>& op) const
810+
constexpr FixMathPrivate::SFixByRange_t<FixMathPrivate::FM_max(NF,_NF),FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)> operator+ (const SFix<_NI,_NF,_RANGE>& op) const
776811
{
777-
using namespace FixMathPrivate;
778-
typedef typename SFix<FM_max(NI,_NI),FM_max(NF,_NF),rangeAdd(NF,_NF,RANGE,_RANGE)>::SFixNIadj_t worktype;
812+
typedef FixMathPrivate::SFixByRange_t<FixMathPrivate::FM_max(NF,_NF),FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)> worktype;
779813
return worktype(worktype(*this).asRaw() + worktype(op).asRaw(), true);
780814
}
781815

@@ -785,7 +819,7 @@ class SFix
785819
@return The result of the addition of op1 and op2. As a SFix
786820
*/
787821
template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
788-
constexpr typename SFix<FixMathPrivate::FM_max(NI,_NI),FixMathPrivate::FM_max(NF,_NF),FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)>::SFixNIadj_t operator+ (const UFix<_NI,_NF,_RANGE>& op2) const
822+
constexpr FixMathPrivate::SFixByRange_t<FixMathPrivate::FM_max(NF,_NF),FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)> operator+ (const UFix<_NI,_NF,_RANGE>& op2) const
789823
{
790824
return op2+(*this);
791825
}
@@ -810,9 +844,9 @@ class SFix
810844
@return The result of the subtraction as a SFix.
811845
*/
812846
template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
813-
constexpr typename SFix<FixMathPrivate::FM_max(NI,_NI),FixMathPrivate::FM_max(NF,_NF),FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)>::SFixNIadj_t operator- (const SFix<_NI,_NF, _RANGE>& op) const
847+
constexpr FixMathPrivate::SFixByRange_t<FixMathPrivate::FM_max(NF,_NF),FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)> operator- (const SFix<_NI,_NF, _RANGE>& op) const
814848
{
815-
typedef typename SFix<FixMathPrivate::FM_max(NI,_NI),FixMathPrivate::FM_max(NF,_NF),FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)>::SFixNIadj_t worktype;
849+
typedef FixMathPrivate::SFixByRange_t<FixMathPrivate::FM_max(NF,_NF),FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)> worktype;
816850
return worktype(worktype(*this).asRaw() - worktype(op).asRaw(), true);
817851
}
818852

@@ -821,9 +855,9 @@ class SFix
821855
@return The result of the subtraction as a SFix.
822856
*/
823857
template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
824-
constexpr typename SFix<FixMathPrivate::FM_max(NI,_NI),FixMathPrivate::FM_max(NF,_NF),FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)>::SFixNIadj_t operator- (const UFix<_NI,_NF, _RANGE>& op) const
858+
constexpr FixMathPrivate::SFixByRange_t<FixMathPrivate::FM_max(NF,_NF),FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)> operator- (const UFix<_NI,_NF, _RANGE>& op) const
825859
{
826-
typedef typename SFix<FixMathPrivate::FM_max(NI,_NI),FixMathPrivate::FM_max(NF,_NF),FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)>::SFixNIadj_t worktype;
860+
typedef FixMathPrivate::SFixByRange_t<FixMathPrivate::FM_max(NF,_NF),FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)> worktype;
827861
return worktype(worktype(*this).asRaw() - worktype(op).asRaw(), true);
828862
}
829863

@@ -855,9 +889,9 @@ class SFix
855889
@return The result of the multiplication as a SFix.
856890
*/
857891
template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
858-
constexpr typename SFix<NI+_NI, NF+_NF, RANGE*_RANGE>::SFixNIadj_t operator* (const SFix<_NI,_NF,_RANGE>& op) const
892+
constexpr FixMathPrivate::SFixByRange_t<NF+_NF, RANGE*_RANGE> operator* (const SFix<_NI,_NF,_RANGE>& op) const
859893
{
860-
typedef typename SFix<NI+_NI, NF+_NF, RANGE*_RANGE>::SFixNIadj_t worktype;
894+
typedef FixMathPrivate::SFixByRange_t<NF+_NF, RANGE*_RANGE> worktype;
861895
return worktype((typename worktype::internal_type)(internal_value)*op.asRaw(), true);
862896
}
863897

@@ -867,7 +901,7 @@ class SFix
867901
@return The result of the multiplication of op1 and op2. As a SFix
868902
*/
869903
template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
870-
constexpr typename SFix<NI+_NI, NF+_NF, RANGE*_RANGE>::SFixNIadj_t operator* (const UFix<_NI,_NF,_RANGE>& op2) const
904+
constexpr FixMathPrivate::SFixByRange_t<NF+_NF, RANGE*_RANGE> operator* (const UFix<_NI,_NF,_RANGE>& op2) const
871905
{
872906
return op2*(*this);
873907
}
@@ -1080,15 +1114,13 @@ class SFix
10801114
*/
10811115
template<int8_t BITS> static constexpr void assertSize() { static_assert(NI+NF+1 <= BITS, "Data type is larger than expected!"); }
10821116
private:
1083-
template<int8_t, int8_t, uint64_t> friend class UFix; // for access to UFixNIadj_t
1117+
template<int8_t, int8_t, uint64_t> friend class UFix; // for access to internal_type
10841118
template<int8_t, int8_t, uint64_t> friend class SFix;
1085-
static constexpr uint64_t maxRANGE(int8_t delta_bits=0) { return (uint64_t(1)<<(NI+NF+delta_bits)); } // no -1 for signed, because negative number actually extend to -2^n, not just 2^n-1
1086-
typedef SFix<(RANGE > maxRANGE()) ? NI+1 : (RANGE > maxRANGE(-1)) ? NI : NI-1, NF, RANGE> SFixNIadj_t;
10871119

10881120
internal_type internal_value;
10891121
//static constexpr internal_type onesbitmask() { return (internal_type) ((1ULL<< (NI+NF)) - 1); }
10901122
static constexpr internal_type onesbitmask() { return (internal_type) ((1ULL<< (NI+NF-1)) + ((1ULL<< (NI+NF-1)) - 1)); }
1091-
static constexpr internal_type msbone() { return (internal_type) (1ULL<< (NI+NF-1)); }
1123+
static constexpr internal_type msbone() { return (internal_type) (1ULL<< (NI+NF-1)); }
10921124
};
10931125

10941126

@@ -1295,14 +1327,18 @@ constexpr bool operator!= (const UFix<NI,NF>& op1, const SFix<_NI,_NF>& op2 )
12951327
////// Helper functions to build SFix from a normal type automatically
12961328

12971329

1298-
/** Create a *pure* fractional signed fixed number (SFix) from a integer.
1330+
/** Create a *pure* fractional signed fixed number (SFix) from an integer.
12991331
The number of fractional bits (NF) is chosen automatically depending on the input
13001332
type. Hence toSFraction(127) and toSFraction(int8_t(127)) *do not* lead to the
13011333
same thing: on an AVR, the former will lead to NF=15 - which is overkill and
13021334
incorrect if you expect toSFraction(127) = 1 -
13031335
whereas the latter will lead to NF=7. Mozzi's objects (Oscil and the like)
13041336
returns correct types, hence you can use this function to convert the return
13051337
value of a Mozzi's function/class member into a pure fractional number.
1338+
1339+
@note If the value is known at compile time, it is much more efficient to
1340+
construct using SFixAuto(), and then shifting to the right.
1341+
13061342
@param val The value to be converted into a pure fractional number.
13071343
@return A SFix<0,NF> with NF chosen according to the input type
13081344
*/
@@ -1311,13 +1347,17 @@ constexpr SFix<0, sizeof(T)*8-1> toSFraction(T val) {
13111347
return SFix<0, sizeof(T)*8-1>::fromRaw(val);
13121348
}
13131349

1314-
/** Create a *pure* integer signed fixed number (SFix) from a integer.
1350+
/** Create a *pure* integer signed fixed number (SFix) from an integer.
13151351
The number of fractional bits (NI) is chosen automatically depending on the input
13161352
type. Hence toSInt(127) and toSInt(int8_t(127)) *do not* lead to the
13171353
same thing: on an AVR, the former will lead to NI=15 - which is overkill -
13181354
whereas the latter will lead to NI=7. Mozzi's objects (Oscil and the like)
13191355
returns correct types, hence you can use this function to convert the return
13201356
value of a Mozzi's function/class member into a pure fractional number.
1357+
1358+
@note If the value is known at compile time, it is much more efficient to
1359+
construct using SFixAuto().
1360+
13211361
@param val The value to be converted into a pure integer fixed math number.
13221362
@return A SFix<NI,0> with NI chosen according to the input type
13231363
*/
@@ -1326,7 +1366,22 @@ constexpr SFix<sizeof(T)*8-1,0> toSInt(T val) {
13261366
return SFix<sizeof(T)*8-1,0>::fromRaw(val);
13271367
}
13281368

1329-
1369+
/** Create a pure integer signed fix number (SFix) from a compile time constant.
1370+
The number of integer bits needed is determined, automatically, based on the actual
1371+
value. This allows to easily create constants requiring minimal storage, without
1372+
counting bits, manually.
1373+
1374+
Examples:
1375+
@code
1376+
auto neg_three = SFixAuto<-3>(); // SFix<2, 0>
1377+
auto ten_point_five = SFixAuto<21>().sR<1>(); // SFix<5, 1>, but consider using
1378+
// UFixAuto() for positive values!
1379+
@endcode
1380+
*/
1381+
template<int64_t value>
1382+
constexpr const FixMathPrivate::SFixByRange_t<0, value < 0 ? -value : value> SFixAuto() {
1383+
return FixMathPrivate::SFixByRange_t<0, value < 0 ? -value : value>::fromRaw(value);
1384+
}
13301385

13311386
#include "FixMath_Autotests.h"
13321387

src/FixMath_Autotests.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,18 @@ namespace FixMathPrivate {
6969
// type conversions
7070
static_assert(a.getNI() == a.asSFix().getNI());
7171
static_assert(a.getNF() == a.asSFix().getNF());
72+
73+
// UFixAuto() / SFixAuto()
74+
static_assert(FixMathPrivate::NIcount<0>() == 0);
75+
static_assert(FixMathPrivate::NIcount<1>() == 1);
76+
static_assert(FixMathPrivate::NIcount<2>() == 2);
77+
static_assert(FixMathPrivate::NIcount<3>() == 2);
78+
static_assert(FixMathPrivate::NIcount<4>() == 3);
79+
80+
UFixAuto<3>().assertSize<2>();
81+
UFixAuto<3>().sR<2>().assertSize<2>();
82+
// TODO: This one could be optimized, further!
83+
SFixAuto<16>().assertSize<6>();
7284
}
7385
}
7486
}

0 commit comments

Comments
 (0)