FixMath
FixMath.h
Go to the documentation of this file.
1 /*
2  * FixMath.h
3  *
4  * Copyright 2023, Thomas Combriat and the Mozzi team
5  *
6  *
7  * FixMath is licensed under a GNU Lesser General Public Licence
8  *
9  */
10 
11 
110 #ifndef FIXMATH2_H_
111 #define FIXMATH2_H_
112 
113 #if FOR_DOXYGEN_ONLY
114 #define FIXMATH_UNSAFE
115 #endif
116 
117 
118 #include<Arduino.h>
119 #include "IntegerType.h"
120 
121 
122 
123 
127 namespace FixMathPrivate {
128  template<typename T> constexpr T shiftR(T x, int8_t bits) {return (bits > 0 ? (x >> (bits)) : bits < 0 ? (x << (-bits)) : x);} // shift right with positive values, left with negative; NOTE: extra condition for bits==0 allows more static tests to work
129  constexpr int8_t sBitsToBytes(int8_t N) { return (((N)>>3)+1);} // conversion between Bits and Bytes for signed
130  constexpr int8_t uBitsToBytes(int8_t N) { return (((N-1)>>3)+1);}
131  template<typename T> constexpr T FM_max(T N1, T N2) { return (N1) > (N2) ? (N1) : (N2);}
132  template<typename T> constexpr T FM_min(T N1, T N2) { return (N1) > (N2) ? (N2) : (N1);}
133  constexpr uint64_t sFullRange(int8_t N) { return uint64_t(1)<<N;} // FM_maximum absolute value that can be hold in a signed of size N
134  constexpr uint64_t uFullRange(int8_t N) { return ((uint64_t(1)<<(N-1))-1) + (uint64_t(1)<<(N-1));}
135  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
136  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.
137 }
138 
139 // Forward declaration
140 template<int8_t NI, int8_t NF, uint64_t RANGE=FixMathPrivate::sFullRange(NI+NF)>
141 class SFix;
142 
143 // Forward declaration
144 template<int8_t NI, int8_t NF, uint64_t RANGE=FixMathPrivate::uFullRange(NI+NF)>
145 class UFix;
146 
147 
148 
154 template<int8_t NI, int8_t NF, uint64_t RANGE> // NI and NF being the number of bits for the integral and the fractionnal parts respectively.
155 class UFix
156 {
157  static_assert(NI+NF<=64, "The total width of a UFix cannot exceed 64bits");
158  typedef typename IntegerType<FixMathPrivate::uBitsToBytes(NI+NF)>::unsigned_type internal_type ; // smallest size that fits our internal integer
159  typedef typename IntegerType<FixMathPrivate::uBitsToBytes(NI+NF+1)>::unsigned_type next_greater_type ; // smallest size that fits 1<<NF for sure (NI could be equal to 0). It can be the same than internal_type in some cases.
160 
161 public:
164  constexpr UFix() {}
165 
170  constexpr UFix(float fl) : internal_value(/*static_cast<internal_type>*/(fl * (next_greater_type(1) << NF))) {}
171 
176  constexpr UFix(double fl) : internal_value(static_cast<internal_type> (fl * (next_greater_type(1) << NF))) {}
177 
178  /* Constructor from integer type (as_frac = false) or from fractionnal value (as_frac=true) can be used to emulate the behavior of for instance Q8n0_to_Q8n8 */
179 
186  template<typename T>
187  constexpr UFix(T value,bool as_raw=false) : internal_value(as_raw ? value : (internal_type(value) << NF)) {}
188 
189 
194  template<typename T>
195  static constexpr UFix<NI,NF> fromRaw(T raw){return UFix<NI,NF>(raw,true);}
196 
197 
198 
199 
200 
205  template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
206  constexpr UFix(const UFix<_NI,_NF, _RANGE>& uf) : internal_value(FixMathPrivate::shiftR((typename IntegerType<FixMathPrivate::uBitsToBytes(FixMathPrivate::FM_max(NI+NF,_NI+_NF))>::unsigned_type) uf.asRaw(),(_NF-NF))) {}
207 
208 
209 
214  template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
215  constexpr UFix(const SFix<_NI,_NF, _RANGE>& uf) : internal_value(FixMathPrivate::shiftR((typename IntegerType<FixMathPrivate::uBitsToBytes(FixMathPrivate::FM_max(NI+NF,_NI+_NF))>::unsigned_type) uf.asRaw(),(_NF-NF))) {}
216 
217 
219 
224  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
226  {
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
230 
231  return worktype(worktype(*this).asRaw() + worktype(op).asRaw(), true);
232  }
233 
238  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
240  {
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;
244 
245  return worktype(worktype(*this).asRaw() + worktype(op).asRaw(), true);
246  }
247 
248 #ifdef FIXMATH_UNSAFE
254  template<typename T>
255  constexpr UFix<NI,NF> operator+ (const T op) const
256  {
257  return UFix<NI,NF>(internal_value+((internal_type)op<<NF),true);
258  }
259 #endif
260 
262 
267  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
269  {
270  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;
272 
273  return worktype(worktype(*this).asRaw() - worktype(op).asRaw(), true);
274  }
275 
281  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
283  {
284  return -op2+(*this);
285  }
286 
287 #ifdef FIXMATH_UNSAFE
293  template<typename T>
294  constexpr UFix<NI,NF> operator- (const T op) const
295  {
296  return UFix<NI,NF>(internal_value-((internal_type)op<<NF),true);
297  }
298 #endif
299 
303  constexpr SFix<NI,NF,RANGE> operator-() const
304  {
305  return SFix<NI,NF,RANGE>( -(typename IntegerType<FixMathPrivate::sBitsToBytes(NI+NF)>::signed_type)(internal_value),true);
306  }
307 
309 
314  template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
316  {
317  typedef typename UFix<NI+_NI, NF+_NF, RANGE*_RANGE>::UFixNIadj_t worktype;
318  return worktype((typename worktype::internal_type) (internal_value)*op.asRaw(), true);
319  }
320 
325  template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
327  {
328  typedef typename SFix<NI+_NI, NF+_NF, RANGE*_RANGE>::SFixNIadj_t worktype;
329  return worktype((typename worktype::internal_type) (internal_value)*op.asRaw(), true);
330  }
331 
332 #ifdef FIXMATH_UNSAFE
338  template<typename T>
339  constexpr UFix<NI,NF> operator* (const T op) const
340  {
341  return UFix<NI,NF>(internal_value*op,true);
342  }
343 #endif
344 
346 
353  constexpr UFix<NF,NI> invFast() const
354  {
355  static_assert(NI+NF<=64, "The fast inverse cannot be computed for when NI+NF>63. Reduce the number of bits.");
356  return UFix<NF,NI>((onesbitmask()/internal_value),true);
357  }
358 
359 
364  template<int8_t _NF>
365  constexpr UFix<NF,_NF> inv() const
366  {
367  return UFix<_NF,NF>(internal_value,true).invFast();
368  }
369 
370 
371 
377  constexpr UFix<NF,FixMathPrivate::FM_min(NI*2+NF,64-NF)> invFull() const // The FixMathPrivate::FM_min is just to remove compiler error when a big FixMath is instanciated but no accurate inverse is actually computed (this would be catch by the static_assert)
378  {
379  static_assert(2*NI+2*NF<=64, "The accurate inverse cannot be computed for when 2*NI+2*NF>63. Reduce the number of bits.");
380  return inv<NI*2+NF>();
381  }
382 
391  template<int8_t _NF=FixMathPrivate::FM_min(NI*2+NF-1,64-NF)>
392  constexpr UFix<NF,_NF> invAccurate() const
393  {
394  static_assert(NF+_NF+1<=64, "The accurate inverse cannot be computed because the asked precision is too great. Reduce the number of bits.");
395  return UFix<NF,_NF>(UFix<NF,_NF+1>::msbone()/internal_value,true);
396  }
397 
398  /* template<int8_t _NF=FixMathPrivate::FM_min(NI*2+NF,64-NF)>
399  constexpr UFix<NF,_NF-1> invAccurateb() const
400  {
401  static_assert(NF+_NF<=64, "The accurate inverse cannot be computed because the asked precision is too great. Reduce the number of bits.");
402  return UFix<NF,_NF-1>(UFix<NF,_NF>::msbone()/internal_value,true);
403  }*/
404 
405 
406  /* template<int8_t _NF=FixMathPrivate::FM_min(NI*2+NF,64-NF)>
407  constexpr UFix<NF,_NF> invAccurate() const
408  {
409  static_assert(NF+_NF<=64, "The accurate inverse cannot be computed because the asked precision is too great. Reduce the number of bits.");
410  return UFix<NF,_NF>(UFix<NF,_NF-1>(UFix<NF,_NF>::msbone()/internal_value,true)); // the last cast is to have the same return type.
411  }*/
412 
413 
414 
415 
417 
423  constexpr UFix<NI,NF> operator>> (const int8_t op) const
424  {
425  return UFix<NI,NF>(internal_value>>op,true);
426  }
427 
428 
429 #ifdef FIXMATH_UNSAFE
436  constexpr UFix<NI,NF> operator<< (const int8_t op) const
437  {
438  return UFix<NI,NF>(internal_value<<op,true);
439  }
440 #endif
441 
446  template<int8_t op>
447  constexpr UFix<FixMathPrivate::FM_max(NI-op,0),NF+op, FixMathPrivate::rangeShift(NI,op,RANGE)> sR() const
448  {
449  return UFix<FixMathPrivate::FM_max(NI-op,0),NF+op,FixMathPrivate::rangeShift(NI,op,RANGE)>(internal_value,true);
450  }
451 
456  template<int8_t op>
457  constexpr UFix<NI+op,FixMathPrivate::FM_max(NF-op,0),FixMathPrivate::rangeShift(NF,op,RANGE)> sL() const
458  {
459  return UFix<NI+op,FixMathPrivate::FM_max(NF-op,0)>(internal_value,true);
460  }
461 
462 
464  /** Comparison with another UFix.
465  @param op A UFix
466  @return true if this is bigger than op, false otherwise
467  */
468  template<int8_t _NI, int8_t _NF>
469  constexpr bool operator> (const UFix<_NI,_NF>& op) const
470  {
471  using namespace FixMathPrivate;
472  typedef UFix<FM_max(NI, _NI),FM_max(NF, _NF)> comptype; // type suitable for comparison
473  return (comptype(*this).asRaw()>comptype(op).asRaw());
474  }
475 
480  template<int8_t _NI, int8_t _NF>
481  constexpr bool operator< (const UFix<_NI,_NF>& op) const
482  {
483  return op > *this;
484  }
485 
486 
491  template<int8_t _NI, int8_t _NF>
492  constexpr bool operator== (const UFix<_NI,_NF>& op) const
493  {
494  using namespace FixMathPrivate;
495  typedef UFix<FM_max(NI, _NI),FM_max(NF, _NF)> comptype; // type suitable for comparison
496  return (comptype(*this).asRaw()==comptype(op).asRaw());
497  }
498 
503  template<int8_t _NI, int8_t _NF>
504  constexpr bool operator!= (const UFix<_NI,_NF>& op) const
505  {
506  typedef UFix<FixMathPrivate::FM_max(NI, _NI),FixMathPrivate::FM_max(NF, _NF)> comptype; // type suitable for comparison
507  return (comptype(*this).asRaw()!=comptype(op).asRaw());
508  }
509 
513  constexpr SFix<NI,NF,RANGE> asSFix() const
514  {
515  return SFix<NI,NF,RANGE>(internal_value,true);
516  }
517 
521  constexpr float asFloat() const { return (static_cast<float>(internal_value)) / (next_greater_type(1)<<NF); }
522 
526  constexpr typename IntegerType<FixMathPrivate::uBitsToBytes(NI)>::unsigned_type asInt() const
527  {
528  return UFix<NI,0>(*this).asRaw();
529  }
530 
534  constexpr internal_type asRaw() const { return internal_value; }
535 
539  static constexpr int8_t getNI() {return NI;}
540 
544  static constexpr int8_t getNF() {return NF;}
545 
562  template<int8_t BITS> static constexpr void assertSize() { static_assert(NI+NF <= BITS, "Data type is larger than expected!"); }
563 private:
564  template<int8_t, int8_t, uint64_t> friend class UFix; // All sibling specializations shall be friends, too
565  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;
568 
569  internal_type internal_value;
570  //static constexpr internal_type onesbitmask() { return (internal_type) ((1ULL<< (NI+NF)) - 1); }
571  static constexpr internal_type onesbitmask() { return (internal_type) ((1ULL<< (NI+NF-1)) + ((1ULL<< (NI+NF-1)) - 1)); }
572  static constexpr internal_type msbone() { return (internal_type) (1ULL<< (NI+NF-1)); }
573 };
574 
575 
576 #ifdef FIXMATH_UNSAFE
577 // Multiplication
578 template <int8_t NI, int8_t NF>
579 constexpr UFix<NI, NF> operator*(uint8_t op, const UFix<NI, NF>& uf) {return uf*op;}
580 
581 template <int8_t NI, int8_t NF>
582 constexpr UFix<NI, NF> operator*(uint16_t op, const UFix<NI, NF>& uf) {return uf*op;}
583 
584 template <int8_t NI, int8_t NF>
585 constexpr UFix<NI, NF> operator*(uint32_t op, const UFix<NI, NF>& uf) {return uf*op;}
586 
587 template <int8_t NI, int8_t NF>
588 constexpr UFix<NI, NF> operator*(uint64_t op, const UFix<NI, NF>& uf) {return uf*op;}
589 
590 template <int8_t NI, int8_t NF>
591 constexpr UFix<NI, NF> operator*(int8_t op, const UFix<NI, NF>& uf) {return uf*op;}
592 
593 template <int8_t NI, int8_t NF>
594 constexpr UFix<NI, NF> operator*(int16_t op, const UFix<NI, NF>& uf) {return uf*op;}
595 
596 template <int8_t NI, int8_t NF>
597 constexpr UFix<NI, NF> operator*(int32_t op, const UFix<NI, NF>& uf) {return uf*op;}
598 
599 template <int8_t NI, int8_t NF>
600 constexpr UFix<NI, NF> operator*(int64_t op, const UFix<NI, NF>& uf) {return uf*op;}
601 
602 template <int8_t NI, int8_t NF>
603 constexpr UFix<NI, NF> operator*(float op, const UFix<NI, NF>& uf) {return uf*op;}
604 
605 template <int8_t NI, int8_t NF>
606 constexpr UFix<NI, NF> operator*(double op, const UFix<NI, NF>& uf) {return uf*op;}
607 
608 // Addition
609 template <int8_t NI, int8_t NF>
610 constexpr UFix<NI, NF> operator+(uint8_t op, const UFix<NI, NF>& uf) {return uf+op;}
611 
612 template <int8_t NI, int8_t NF>
613 constexpr UFix<NI, NF> operator+(uint16_t op, const UFix<NI, NF>& uf) {return uf+op;}
614 
615 template <int8_t NI, int8_t NF>
616 constexpr UFix<NI, NF> operator+(uint32_t op, const UFix<NI, NF>& uf) {return uf+op;}
617 
618 template <int8_t NI, int8_t NF>
619 constexpr UFix<NI, NF> operator+(uint64_t op, const UFix<NI, NF>& uf) {return uf+op;}
620 
621 template <int8_t NI, int8_t NF>
622 constexpr UFix<NI, NF> operator+(int8_t op, const UFix<NI, NF>& uf) {return uf+op;}
623 
624 template <int8_t NI, int8_t NF>
625 constexpr UFix<NI, NF> operator+(int16_t op, const UFix<NI, NF>& uf) {return uf+op;}
626 
627 template <int8_t NI, int8_t NF>
628 constexpr UFix<NI, NF> operator+(int32_t op, const UFix<NI, NF>& uf) {return uf+op;}
629 
630 template <int8_t NI, int8_t NF>
631 constexpr UFix<NI, NF> operator+(int64_t op, const UFix<NI, NF>& uf) {return uf+op;}
632 
633 template <int8_t NI, int8_t NF>
634 constexpr UFix<NI, NF> operator+(float op, const UFix<NI, NF>& uf) {return uf+op;}
635 
636 template <int8_t NI, int8_t NF>
637 constexpr UFix<NI, NF> operator+(double op, const UFix<NI, NF>& uf) {return uf+op;}
638 
639 // Substraction
640 template <int8_t NI, int8_t NF>
641 constexpr SFix<NI, NF> operator-(uint8_t op, const UFix<NI, NF>& uf) {return -uf+op;}
642 
643 template <int8_t NI, int8_t NF>
644 constexpr SFix<NI, NF> operator-(uint16_t op, const UFix<NI, NF>& uf) {return -uf+op;}
645 
646 template <int8_t NI, int8_t NF>
647 constexpr SFix<NI, NF> operator-(uint32_t op, const UFix<NI, NF>& uf) {return -uf+op;}
648 
649 template <int8_t NI, int8_t NF>
650 constexpr SFix<NI, NF> operator-(uint64_t op, const UFix<NI, NF>& uf) {return -uf+op;}
651 
652 template <int8_t NI, int8_t NF>
653 constexpr SFix<NI, NF> operator-(int8_t op, const UFix<NI, NF>& uf) {return -uf+op;}
654 
655 template <int8_t NI, int8_t NF>
656 constexpr SFix<NI, NF> operator-(int16_t op, const UFix<NI, NF>& uf) {return -uf+op;}
657 
658 template <int8_t NI, int8_t NF>
659 constexpr SFix<NI, NF> operator-(int32_t op, const UFix<NI, NF>& uf) {return -uf+op;}
660 
661 template <int8_t NI, int8_t NF>
662 constexpr SFix<NI, NF> operator-(int64_t op, const UFix<NI, NF>& uf) {return -uf+op;}
663 
664 template <int8_t NI, int8_t NF>
665 constexpr SFix<NI, NF> operator-(float op, const UFix<NI, NF>& uf) {return -uf+op;}
666 
667 template <int8_t NI, int8_t NF>
668 constexpr SFix<NI, NF> operator-(double op, const UFix<NI, NF>& uf) {return -uf+op;}
669 #endif
671 
672 
684 template<typename T>
685 constexpr inline UFix<0, sizeof(T)*8> toUFraction(T val) {
686  return UFix<0, sizeof(T)*8>::fromRaw(val);
687 }
688 
699 template<typename T>
700 constexpr inline UFix<sizeof(T)*8,0> toUInt(T val) {
701  return UFix<sizeof(T)*8,0>::fromRaw(val);
702 }
703 
704 
705 
712 template<int8_t NI, int8_t NF, uint64_t RANGE> // NI and NF being the number of bits for the integral and the fractionnal parts respectively.
713 class SFix
714 {
715  static_assert(NI+NF<64, "The total width of a SFix cannot exceed 63bits");
716  typedef typename IntegerType<FixMathPrivate::sBitsToBytes(NI+NF)>::signed_type internal_type ; // smallest size that fits our internal integer
717  typedef typename IntegerType<FixMathPrivate::sBitsToBytes(NI+NF+1)>::signed_type next_greater_type ; // smallest size that fits 1<<NF for sure (NI could be equal to 0). It can be the same than internal_type in some cases.
718 
719 public:
722  constexpr SFix() {}
723 
728  constexpr SFix(float fl) : internal_value(/*static_cast<internal_type>*/(fl * (next_greater_type(1) << NF))) {}
729 
734  constexpr SFix(double fl) : internal_value(static_cast<internal_type> (fl * (next_greater_type(1) << NF))) {}
735 
736 
743  template<typename T>
744  constexpr SFix(T value,bool as_raw=false) : internal_value(as_raw ? value : (internal_type(value) << NF)) {};
745 
750  template<typename T>
751  static constexpr SFix<NI,NF> fromRaw(T raw){return SFix<NI,NF>(raw,true);}
752 
753 
758  template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
759  constexpr SFix(const SFix<_NI,_NF, _RANGE>& sf) : internal_value(FixMathPrivate::shiftR((typename IntegerType<FixMathPrivate::sBitsToBytes(FixMathPrivate::FM_max(NI+NF,_NI+_NF))>::signed_type) sf.asRaw(),(_NF-NF))) {}
760 
765  template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
766  constexpr SFix(const UFix<_NI,_NF, _RANGE>& uf) : internal_value(FixMathPrivate::shiftR((typename IntegerType<FixMathPrivate::uBitsToBytes(FixMathPrivate::FM_max(NI+NF,_NI+_NF))>::unsigned_type) uf.asRaw(),(_NF-NF))) {};
767 
769 
774  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
776  {
777  using namespace FixMathPrivate;
778  typedef typename SFix<FM_max(NI,_NI),FM_max(NF,_NF),rangeAdd(NF,_NF,RANGE,_RANGE)>::SFixNIadj_t worktype;
779  return worktype(worktype(*this).asRaw() + worktype(op).asRaw(), true);
780  }
781 
787  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
789  {
790  return op2+(*this);
791  }
792 
793 #ifdef FIXMATH_UNSAFE
799  template<typename T>
800  constexpr SFix<NI,NF> operator+ (const T op) const
801  {
802  return SFix<NI,NF>(internal_value+(op<<NF),true);
803  }
804 #endif
805 
807 
812  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
814  {
815  typedef typename SFix<FixMathPrivate::FM_max(NI,_NI),FixMathPrivate::FM_max(NF,_NF),FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)>::SFixNIadj_t worktype;
816  return worktype(worktype(*this).asRaw() - worktype(op).asRaw(), true);
817  }
818 
823  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
825  {
826  typedef typename SFix<FixMathPrivate::FM_max(NI,_NI),FixMathPrivate::FM_max(NF,_NF),FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)>::SFixNIadj_t worktype;
827  return worktype(worktype(*this).asRaw() - worktype(op).asRaw(), true);
828  }
829 
830 #ifdef FIXMATH_UNSAFE
836  template<typename T>
837  constexpr SFix<NI,NF> operator- (const T op) const
838  {
839  return SFix<NI,NF>(internal_value-(op<<NF),true);
840  }
841 #endif
842 
846  constexpr SFix<NI,NF,RANGE> operator-() const
847  {
848  return SFix<NI,NF,RANGE>(-internal_value,true);
849  }
850 
852 
857  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
859  {
860  typedef typename SFix<NI+_NI, NF+_NF, RANGE*_RANGE>::SFixNIadj_t worktype;
861  return worktype((typename worktype::internal_type)(internal_value)*op.asRaw(), true);
862  }
863 
869  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
871  {
872  return op2*(*this);
873  }
874 
875 #ifdef FIXMATH_UNSAFE
881  template<typename T>
882  constexpr SFix<NI,NF> operator* (const T op) const
883  {
884  return SFix<NI,NF>(internal_value*op,true);
885  }
886 #endif
887 
888 
890 
898  constexpr SFix<NF,NI> invFast() const
899  {
900  static_assert(NI+NF<=63, "The fast inverse cannot be computed for when NI+NF>63. Reduce the number of bits.");
901  return SFix<NF,NI>((onesbitmask()/internal_value),true);
902  }
903 
908  template<int8_t _NF>
909  constexpr SFix<NF,_NF> inv() const
910  {
911  return SFix<_NF,NF>(internal_value,true).invFast();
912  }
913 
919  constexpr SFix<NF,FixMathPrivate::FM_min(NI*2+NF,63-NF)> invFull() const
920  {
921  return inv<NI*2+NF>();
922  }
923 
924 
933  template<int8_t _NF=FixMathPrivate::FM_min(NI*2+NF-1,63-NF)>
934  constexpr SFix<NF,_NF> invAccurate() const
935  {
936  static_assert(NF+_NF+1<=63, "The accurate inverse cannot be computed because the asked precision is too great. Reduce the number of bits.");
937  return SFix<NF,_NF>(SFix<NF,_NF+1>::msbone()/internal_value,true);
938  }
939 
940 
942 
948  constexpr SFix<NI,NF> operator>> (const int8_t op) const
949  {
950  return SFix<NI,NF>(internal_value>>op,true);
951  }
952 
953 #ifdef FIXMATH_UNSAFE
960  constexpr SFix<NI,NF> operator<< (const int8_t op) const
961  {
962  return SFix<NI,NF>(internal_value<<op,true);
963  }
964 #endif
965 
970  template<int8_t op>
971  constexpr SFix<FixMathPrivate::FM_max(NI-op,0), NF+op, FixMathPrivate::rangeShift(NI,op,RANGE)> sR()
972  {
973  return SFix<FixMathPrivate::FM_max(NI-op,0),NF+op,FixMathPrivate::rangeShift(NI,op,RANGE)>(internal_value,true);
974  }
975 
980  template<int8_t op>
981  constexpr SFix<NI+op,FixMathPrivate::FM_max(NF-op,0),FixMathPrivate::rangeShift(NF,op,RANGE)> sL()
982  {
983  return SFix<NI+op,FixMathPrivate::FM_max(NF-op,0)>(internal_value,true);
984  }
985 
986 
988 
993  template<int8_t _NI, int8_t _NF>
994  constexpr bool operator> (const SFix<_NI,_NF>& op) const
995  {
996  using namespace FixMathPrivate;
997  typedef SFix<FM_max(NI, _NI), FM_max(NF, _NF)> comptype; // common type suitable for comparison
998  return comptype(*this).asRaw()>comptype(op).asRaw();
999  }
1000 
1005  template<int8_t _NI, int8_t _NF>
1006  constexpr bool operator< (const SFix<_NI,_NF>& op) const
1007  {
1008  return op > *this;
1009  }
1010 
1011 
1016  template<int8_t _NI, int8_t _NF>
1017  constexpr bool operator== (const SFix<_NI,_NF>& op) const
1018  {
1019  using namespace FixMathPrivate;
1020  typedef SFix<FM_max(NI, _NI), FM_max(NF, _NF)> comptype; // common type suitable for comparison
1021  return comptype(*this).asRaw()==comptype(op).asRaw();
1022  }
1023 
1028  template<int8_t _NI, int8_t _NF>
1029  constexpr bool operator!= (const SFix<_NI,_NF>& op) const
1030  {
1031  typedef SFix<FixMathPrivate::FM_max(NI, _NI), FixMathPrivate::FM_max(NF, _NF)> comptype; // common type suitable for comparison
1032  return comptype(*this).asRaw()!=comptype(op).asRaw();
1033  }
1034 
1035 
1039  constexpr UFix<NI,NF,RANGE> asUFix() const
1040  {
1041  return UFix<NI,NF,RANGE>(internal_value,true);
1042  }
1043 
1044 
1048  constexpr float asFloat() const {return (static_cast<float>(internal_value)) / (next_greater_type(1)<<NF); }
1049 
1054  constexpr typename IntegerType<FixMathPrivate::sBitsToBytes(NI+1)>::signed_type asInt() const // the +1 is to ensure that no overflow occurs at the lower end of the container (ie when getting the integer part of SFix<7,N>(-128.4), which is a valid SFix<7,N>) because the floor is done towards negative values.
1055  {
1056  SFix<NI+1,0> integer_part(*this);
1057  return integer_part.asRaw();
1058  }
1059 
1063  constexpr internal_type asRaw() const {return internal_value; }
1064 
1068  static constexpr int8_t getNI() {return NI;}
1069 
1073  static constexpr int8_t getNF() {return NF;}
1074 
1075 
1081  template<int8_t BITS> static constexpr void assertSize() { static_assert(NI+NF+1 <= BITS, "Data type is larger than expected!"); }
1082 private:
1083  template<int8_t, int8_t, uint64_t> friend class UFix; // for access to UFixNIadj_t
1084  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 UFix<(RANGE > maxRANGE()) ? NI+1 : (RANGE > maxRANGE(-1)) ? NI : NI-1, NF, RANGE> SFixNIadj_t;
1087 
1088  internal_type internal_value;
1089  //static constexpr internal_type onesbitmask() { return (internal_type) ((1ULL<< (NI+NF)) - 1); }
1090  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)); }
1092 };
1093 
1094 
1095 #ifdef FIXMATH_UNSAFE
1097 
1098 // Multiplication
1099 template <int8_t NI, int8_t NF>
1100 constexpr SFix<NI, NF> operator*(uint8_t op, const SFix<NI, NF>& uf) {return uf*op;}
1101 
1102 template <int8_t NI, int8_t NF>
1103 constexpr SFix<NI, NF> operator*(uint16_t op, const SFix<NI, NF>& uf) {return uf*op;}
1104 
1105 template <int8_t NI, int8_t NF>
1106 constexpr SFix<NI, NF> operator*(uint32_t op, const SFix<NI, NF>& uf) {return uf*op;}
1107 
1108 template <int8_t NI, int8_t NF>
1109 constexpr SFix<NI, NF> operator*(uint64_t op, const SFix<NI, NF>& uf) {return uf*op;}
1110 
1111 template <int8_t NI, int8_t NF>
1112 constexpr SFix<NI, NF> operator*(int8_t op, const SFix<NI, NF>& uf) {return uf*op;}
1113 
1114 template <int8_t NI, int8_t NF>
1115 constexpr SFix<NI, NF> operator*(int16_t op, const SFix<NI, NF>& uf) {return uf*op;}
1116 
1117 template <int8_t NI, int8_t NF>
1118 constexpr SFix<NI, NF> operator*(int32_t op, const SFix<NI, NF>& uf) {return uf*op;}
1119 
1120 template <int8_t NI, int8_t NF>
1121 constexpr SFix<NI, NF> operator*(int64_t op, const SFix<NI, NF>& uf) {return uf*op;}
1122 
1123 template <int8_t NI, int8_t NF>
1124 constexpr SFix<NI, NF> operator*(float op, const SFix<NI, NF>& uf) {return uf*op;}
1125 
1126 template <int8_t NI, int8_t NF>
1127 constexpr SFix<NI, NF> operator*(double op, const SFix<NI, NF>& uf) {return uf*op;}
1128 
1129 // Addition
1130 template <int8_t NI, int8_t NF>
1131 constexpr SFix<NI, NF> operator+(uint8_t op, const SFix<NI, NF>& uf) {return uf+op;}
1132 
1133 template <int8_t NI, int8_t NF>
1134 constexpr SFix<NI, NF> operator+(uint16_t op, const SFix<NI, NF>& uf) {return uf+op;}
1135 
1136 template <int8_t NI, int8_t NF>
1137 constexpr SFix<NI, NF> operator+(uint32_t op, const SFix<NI, NF>& uf) {return uf+op;}
1138 
1139 template <int8_t NI, int8_t NF>
1140 constexpr SFix<NI, NF> operator+(uint64_t op, const SFix<NI, NF>& uf) {return uf+op;}
1141 
1142 template <int8_t NI, int8_t NF>
1143 constexpr SFix<NI, NF> operator+(int8_t op, const SFix<NI, NF>& uf) {return uf+op;}
1144 
1145 template <int8_t NI, int8_t NF>
1146 constexpr SFix<NI, NF> operator+(int16_t op, const SFix<NI, NF>& uf) {return uf+op;}
1147 
1148 template <int8_t NI, int8_t NF>
1149 constexpr SFix<NI, NF> operator+(int32_t op, const SFix<NI, NF>& uf) {return uf+op;}
1150 
1151 template <int8_t NI, int8_t NF>
1152 constexpr SFix<NI, NF> operator+(int64_t op, const SFix<NI, NF>& uf) {return uf+op;}
1153 
1154 template <int8_t NI, int8_t NF>
1155 constexpr SFix<NI, NF> operator+(float op, const SFix<NI, NF>& uf) {return uf+op;}
1156 
1157 template <int8_t NI, int8_t NF>
1158 constexpr SFix<NI, NF> operator+(double op, const SFix<NI, NF>& uf) {return uf+op;}
1159 
1160 // Substraction
1161 template <int8_t NI, int8_t NF>
1162 constexpr SFix<NI, NF> operator-(uint8_t op, const SFix<NI, NF>& uf) {return (-uf)+op;}
1163 
1164 template <int8_t NI, int8_t NF>
1165 constexpr SFix<NI, NF> operator-(uint16_t op, const SFix<NI, NF>& uf) {return (-uf)+op;}
1166 
1167 template <int8_t NI, int8_t NF>
1168 constexpr SFix<NI, NF> operator-(uint32_t op, const SFix<NI, NF>& uf) {return (-uf)+op;}
1169 
1170 template <int8_t NI, int8_t NF>
1171 constexpr SFix<NI, NF> operator-(uint64_t op, const SFix<NI, NF>& uf) {return (-uf)+op;}
1172 
1173 template <int8_t NI, int8_t NF>
1174 constexpr SFix<NI, NF> operator-(int8_t op, const SFix<NI, NF>& uf) {return (-uf)+op;}
1175 
1176 template <int8_t NI, int8_t NF>
1177 constexpr SFix<NI, NF> operator-(int16_t op, const SFix<NI, NF>& uf) {return (-uf)+op;}
1178 
1179 template <int8_t NI, int8_t NF>
1180 constexpr SFix<NI, NF> operator-(int32_t op, const SFix<NI, NF>& uf) {return (-uf)+op;}
1181 
1182 template <int8_t NI, int8_t NF>
1183 constexpr SFix<NI, NF> operator-(int64_t op, const SFix<NI, NF>& uf) {return (-uf)+op;}
1184 
1185 template <int8_t NI, int8_t NF>
1186 constexpr SFix<NI, NF> operator-(float op, const SFix<NI, NF>& uf) {return (-uf)+op;}
1187 
1188 template <int8_t NI, int8_t NF>
1189 constexpr SFix<NI, NF> operator-(double op, const SFix<NI, NF>& uf) {return (-uf)+op;}
1190 
1191 #endif
1192 
1193 
1194 
1195 
1196 
1197 // Comparison between SFix and UFix
1198 
1204 template<int8_t NI, int8_t NF, int8_t _NI, int8_t _NF>
1205 constexpr bool operator> (const SFix<NI,NF>& op1, const UFix<_NI,_NF>& op2 )
1206 {
1207  typedef SFix<FixMathPrivate::FM_max(NI, _NI), FixMathPrivate::FM_max(NF, _NF)> worktype;
1208  return worktype(op1).asRaw() > worktype(op2).asRaw();
1209 }
1210 
1216 template<int8_t NI, int8_t NF, int8_t _NI, int8_t _NF>
1217 constexpr bool operator> (const UFix<NI,NF>& op1, const SFix<_NI,_NF>& op2 )
1218 {
1219  typedef SFix<FixMathPrivate::FM_max(NI, _NI), FixMathPrivate::FM_max(NF, _NF)> worktype;
1220  return worktype(op1).asRaw() > worktype(op2).asRaw();
1221 }
1222 
1228 template<int8_t NI, int8_t NF, int8_t _NI, int8_t _NF>
1229 constexpr bool operator< (const UFix<NI,NF>& op1, const SFix<_NI,_NF>& op2 )
1230 {
1231  return op2 > op1;
1232 }
1233 
1234 
1240 template<int8_t NI, int8_t NF, int8_t _NI, int8_t _NF>
1241 constexpr bool operator< (const SFix<NI,NF>& op1, const UFix<_NI,_NF>& op2 )
1242 {
1243  return op2 > op1;
1244 }
1245 
1246 
1252 template<int8_t NI, int8_t NF, int8_t _NI, int8_t _NF>
1253 constexpr bool operator== (const SFix<NI,NF>& op1, const UFix<_NI,_NF>& op2)
1254 {
1255  typedef SFix<FixMathPrivate::FM_max(NI, _NI), FixMathPrivate::FM_max(NF, _NF)> worktype;
1256  return (worktype(op1).asRaw() == worktype(op2).asRaw());
1257 }
1258 
1259 
1265 template<int8_t NI, int8_t NF, int8_t _NI, int8_t _NF>
1266 constexpr bool operator== (const UFix<NI,NF>& op1, const SFix<_NI,_NF>& op2 )
1267 {
1268  return op2 == op1;
1269 }
1270 
1276 template<int8_t NI, int8_t NF, int8_t _NI, int8_t _NF>
1277 constexpr bool operator!= (const SFix<NI,NF>& op1, const UFix<_NI,_NF>& op2 )
1278 {
1279  return !(op1 == op2);
1280 }
1281 
1282 
1288 template<int8_t NI, int8_t NF, int8_t _NI, int8_t _NF>
1289 constexpr bool operator!= (const UFix<NI,NF>& op1, const SFix<_NI,_NF>& op2 )
1290 {
1291  typedef SFix<FixMathPrivate::FM_max(NI, _NI), FixMathPrivate::FM_max(NF, _NF)> comptype;
1292  return (comptype(op1).asRaw() != comptype(op2).asRaw());;
1293 }
1294 
1296 
1297 
1309 template<typename T>
1310 constexpr SFix<0, sizeof(T)*8-1> toSFraction(T val) {
1311  return SFix<0, sizeof(T)*8-1>::fromRaw(val);
1312 }
1313 
1324 template<typename T>
1325 constexpr SFix<sizeof(T)*8-1,0> toSInt(T val) {
1326  return SFix<sizeof(T)*8-1,0>::fromRaw(val);
1327 }
1328 
1329 
1330 
1331 #include "FixMath_Autotests.h"
1332 
1333 
1334 #endif
Definition: FixMath.h:714
constexpr internal_type asRaw() const
Definition: FixMath.h:1063
Definition: FixMath.h:156
constexpr SFix< NI, NF, RANGE > operator-() const
Definition: FixMath.h:303
constexpr internal_type asRaw() const
Definition: FixMath.h:534
constexpr UFix(float fl)
Definition: FixMath.h:170
constexpr UFix(double fl)
Definition: FixMath.h:176
constexpr UFix< NI+_NI, NF+_NF, RANGE *_RANGE >::UFixNIadj_t operator*(const UFix< _NI, _NF, _RANGE > &op) const
Definition: FixMath.h:315
constexpr UFix(T value, bool as_raw=false)
Definition: FixMath.h:187
constexpr UFix()
Definition: FixMath.h:164
constexpr UFix< NF, NI > invFast() const
Definition: FixMath.h:353
static constexpr UFix< NI, NF > fromRaw(T raw)
Definition: FixMath.h:195
constexpr UFix(const UFix< _NI, _NF, _RANGE > &uf)
Definition: FixMath.h:206
constexpr 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
Definition: FixMath.h:225
constexpr UFix(const SFix< _NI, _NF, _RANGE > &uf)
Definition: FixMath.h:215
Definition: FixMath.h:127
Definition: IntegerType.h:9