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 
126 namespace FixMathPrivate {
127  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
128  constexpr int8_t sBitsToBytes(int8_t N) { return (((N)>>3)+1);} // conversion between Bits and Bytes for signed
129  constexpr int8_t uBitsToBytes(int8_t N) { return (((N-1)>>3)+1);}
130  template<typename T> constexpr T FM_max(T N1, T N2) { return (N1) > (N2) ? (N1) : (N2);}
131  template<typename T> constexpr T FM_min(T N1, T N2) { return (N1) > (N2) ? (N2) : (N1);}
132  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
133  constexpr uint64_t uFullRange(int8_t N) { return ((uint64_t(1)<<(N-1))-1) + (uint64_t(1)<<(N-1));}
134  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
135  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(); };
146 }
147 
148 // Forward declaration
149 template<int8_t NI, int8_t NF, uint64_t RANGE=FixMathPrivate::sFullRange(NI+NF)>
150 class SFix;
151 
152 // Forward declaration
153 template<int8_t NI, int8_t NF, uint64_t RANGE=FixMathPrivate::uFullRange(NI+NF)>
154 class UFix;
155 
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-1>()-NF, NF, RANGE>;
161 }
162 
168 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.
169 class UFix
170 {
171  static_assert(NI+NF<=64, "The total width of a UFix cannot exceed 64bits");
172  typedef typename IntegerType<FixMathPrivate::uBitsToBytes(NI+NF)>::unsigned_type internal_type ; // smallest size that fits our internal integer
173  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.
174 
175 public:
178  constexpr UFix() {}
179 
184  constexpr UFix(float fl) : internal_value(/*static_cast<internal_type>*/(fl * (next_greater_type(1) << NF))) {}
185 
190  constexpr UFix(double fl) : internal_value(static_cast<internal_type> (fl * (next_greater_type(1) << NF))) {}
191 
192  /* 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 */
193 
200  template<typename T>
201  constexpr UFix(T value,bool as_raw=false) : internal_value(as_raw ? value : (internal_type(value) << NF)) {}
202 
203 
208  template<typename T>
209  static constexpr UFix<NI,NF> fromRaw(T raw){return UFix<NI,NF>(raw,true);}
210 
211 
212 
213 
214 
219  template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
220  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))) {}
221 
222 
223 
228  template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
229  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))) {}
230 
231 
233 
238  template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
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
240  {
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;
243 
244  return worktype(worktype(*this).asRaw() + worktype(op).asRaw(), true);
245  }
246 
251  template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
252  constexpr FixMathPrivate::SFixByRange_t<FixMathPrivate::FM_max(NF,_NF), FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)> operator+ (const SFix<_NI,_NF,_RANGE>& op) const
253  {
254  typedef FixMathPrivate::SFixByRange_t<FixMathPrivate::FM_max(NF,_NF), FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)> worktype;
255 
256  return worktype(worktype(*this).asRaw() + worktype(op).asRaw(), true);
257  }
258 
259 #ifdef FIXMATH_UNSAFE
265  template<typename T>
266  constexpr UFix<NI,NF> operator+ (const T op) const
267  {
268  return UFix<NI,NF>(internal_value+((internal_type)op<<NF),true);
269  }
270 #endif
271 
273 
278  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.
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
280  {
281  using namespace FixMathPrivate;
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;
283 
284  return worktype(worktype(*this).asRaw() - worktype(op).asRaw(), true);
285  }
286 
292  template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
293  constexpr FixMathPrivate::SFixByRange_t<FixMathPrivate::FM_max(NF,_NF), FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)> operator- (const SFix<_NI,_NF, _RANGE>& op2) const
294  {
295  return -op2+(*this);
296  }
297 
298 #ifdef FIXMATH_UNSAFE
304  template<typename T>
305  constexpr UFix<NI,NF> operator- (const T op) const
306  {
307  return UFix<NI,NF>(internal_value-((internal_type)op<<NF),true);
308  }
309 #endif
310 
314  constexpr SFix<NI,NF,RANGE> operator-() const
315  {
316  return SFix<NI,NF,RANGE>( -(typename IntegerType<FixMathPrivate::sBitsToBytes(NI+NF)>::signed_type)(internal_value),true);
317  }
318 
320 
325  template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
327  {
329  return worktype((typename worktype::internal_type) (internal_value)*op.asRaw(), true);
330  }
331 
336  template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
338  {
340  return worktype((typename worktype::internal_type) (internal_value)*op.asRaw(), true);
341  }
342 
343 #ifdef FIXMATH_UNSAFE
349  template<typename T>
350  constexpr UFix<NI,NF> operator* (const T op) const
351  {
352  return UFix<NI,NF>(internal_value*op,true);
353  }
354 #endif
355 
357 
364  constexpr UFix<NF,NI> invFast() const
365  {
366  static_assert(NI+NF<=64, "The fast inverse cannot be computed for when NI+NF>63. Reduce the number of bits.");
367  return UFix<NF,NI>((onesbitmask()/internal_value),true);
368  }
369 
370 
375  template<int8_t _NF>
376  constexpr UFix<NF,_NF> inv() const
377  {
378  return UFix<_NF,NF>(internal_value,true).invFast();
379  }
380 
381 
382 
388  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)
389  {
390  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.");
391  return inv<NI*2+NF>();
392  }
393 
402  template<int8_t _NF=FixMathPrivate::FM_min(NI*2+NF-1,64-NF)>
403  constexpr UFix<NF,_NF> invAccurate() const
404  {
405  static_assert(NF+_NF+1<=64, "The accurate inverse cannot be computed because the asked precision is too great. Reduce the number of bits.");
406  return UFix<NF,_NF>(UFix<NF,_NF+1>::msbone()/internal_value,true);
407  }
408 
409  /* template<int8_t _NF=FixMathPrivate::FM_min(NI*2+NF,64-NF)>
410  constexpr UFix<NF,_NF-1> invAccurateb() const
411  {
412  static_assert(NF+_NF<=64, "The accurate inverse cannot be computed because the asked precision is too great. Reduce the number of bits.");
413  return UFix<NF,_NF-1>(UFix<NF,_NF>::msbone()/internal_value,true);
414  }*/
415 
416 
417  /* template<int8_t _NF=FixMathPrivate::FM_min(NI*2+NF,64-NF)>
418  constexpr UFix<NF,_NF> invAccurate() const
419  {
420  static_assert(NF+_NF<=64, "The accurate inverse cannot be computed because the asked precision is too great. Reduce the number of bits.");
421  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.
422  }*/
423 
424 
425 
426 
428 
434  constexpr UFix<NI,NF> operator>> (const int8_t op) const
435  {
436  return UFix<NI,NF>(internal_value>>op,true);
437  }
438 
439 
440 #ifdef FIXMATH_UNSAFE
447  constexpr UFix<NI,NF> operator<< (const int8_t op) const
448  {
449  return UFix<NI,NF>(internal_value<<op,true);
450  }
451 #endif
452 
457  template<int8_t op>
458  constexpr UFix<FixMathPrivate::FM_max(NI-op,0),NF+op, FixMathPrivate::rangeShift(NI,op,RANGE)> sR() const
459  {
460  return UFix<FixMathPrivate::FM_max(NI-op,0),NF+op,FixMathPrivate::rangeShift(NI,op,RANGE)>(internal_value,true);
461  }
462 
467  template<int8_t op>
468  constexpr UFix<NI+op,FixMathPrivate::FM_max(NF-op,0),FixMathPrivate::rangeShift(NF,op,RANGE)> sL() const
469  {
470  return UFix<NI+op,FixMathPrivate::FM_max(NF-op,0)>(internal_value,true);
471  }
472 
473 
475  /** Comparison with another UFix.
476  @param op A UFix
477  @return true if this is bigger than op, false otherwise
478  */
479  template<int8_t _NI, int8_t _NF>
480  constexpr bool operator> (const UFix<_NI,_NF>& op) const
481  {
482  using namespace FixMathPrivate;
483  typedef UFix<FM_max(NI, _NI),FM_max(NF, _NF)> comptype; // type suitable for comparison
484  return (comptype(*this).asRaw()>comptype(op).asRaw());
485  }
486 
491  template<int8_t _NI, int8_t _NF>
492  constexpr bool operator< (const UFix<_NI,_NF>& op) const
493  {
494  return op > *this;
495  }
496 
497 
502  template<int8_t _NI, int8_t _NF>
503  constexpr bool operator== (const UFix<_NI,_NF>& op) const
504  {
505  using namespace FixMathPrivate;
506  typedef UFix<FM_max(NI, _NI),FM_max(NF, _NF)> comptype; // type suitable for comparison
507  return (comptype(*this).asRaw()==comptype(op).asRaw());
508  }
509 
514  template<int8_t _NI, int8_t _NF>
515  constexpr bool operator!= (const UFix<_NI,_NF>& op) const
516  {
517  typedef UFix<FixMathPrivate::FM_max(NI, _NI),FixMathPrivate::FM_max(NF, _NF)> comptype; // type suitable for comparison
518  return (comptype(*this).asRaw()!=comptype(op).asRaw());
519  }
520 
524  constexpr SFix<NI,NF,RANGE> asSFix() const
525  {
526  return SFix<NI,NF,RANGE>(internal_value,true);
527  }
528 
532  constexpr float asFloat() const { return (static_cast<float>(internal_value)) / (next_greater_type(1)<<NF); }
533 
537  constexpr typename IntegerType<FixMathPrivate::uBitsToBytes(NI)>::unsigned_type asInt() const
538  {
539  return UFix<NI,0>(*this).asRaw();
540  }
541 
545  constexpr internal_type asRaw() const { return internal_value; }
546 
550  static constexpr int8_t getNI() {return NI;}
551 
555  static constexpr int8_t getNF() {return NF;}
556 
560  static constexpr int8_t getRANGE() {return RANGE;}
561 
578  template<int8_t BITS> static constexpr void assertSize() { static_assert(NI+NF <= BITS, "Data type is larger than expected!"); }
579 private:
580  template<int8_t, int8_t, uint64_t> friend class UFix; // for access to internal_type
581  template<int8_t, int8_t, uint64_t> friend class SFix;
582 
583  internal_type internal_value;
584  //static constexpr internal_type onesbitmask() { return (internal_type) ((1ULL<< (NI+NF)) - 1); }
585  static constexpr internal_type onesbitmask() { return (internal_type) ((1ULL<< (NI+NF-1)) + ((1ULL<< (NI+NF-1)) - 1)); }
586  static constexpr internal_type msbone() { return (internal_type) (1ULL<< (NI+NF-1)); }
587 };
588 
589 
590 #ifdef FIXMATH_UNSAFE
591 // Multiplication
592 template <int8_t NI, int8_t NF>
593 constexpr UFix<NI, NF> operator*(uint8_t op, const UFix<NI, NF>& uf) {return uf*op;}
594 
595 template <int8_t NI, int8_t NF>
596 constexpr UFix<NI, NF> operator*(uint16_t op, const UFix<NI, NF>& uf) {return uf*op;}
597 
598 template <int8_t NI, int8_t NF>
599 constexpr UFix<NI, NF> operator*(uint32_t op, const UFix<NI, NF>& uf) {return uf*op;}
600 
601 template <int8_t NI, int8_t NF>
602 constexpr UFix<NI, NF> operator*(uint64_t op, const UFix<NI, NF>& uf) {return uf*op;}
603 
604 template <int8_t NI, int8_t NF>
605 constexpr UFix<NI, NF> operator*(int8_t op, const UFix<NI, NF>& uf) {return uf*op;}
606 
607 template <int8_t NI, int8_t NF>
608 constexpr UFix<NI, NF> operator*(int16_t op, const UFix<NI, NF>& uf) {return uf*op;}
609 
610 template <int8_t NI, int8_t NF>
611 constexpr UFix<NI, NF> operator*(int32_t op, const UFix<NI, NF>& uf) {return uf*op;}
612 
613 template <int8_t NI, int8_t NF>
614 constexpr UFix<NI, NF> operator*(int64_t op, const UFix<NI, NF>& uf) {return uf*op;}
615 
616 template <int8_t NI, int8_t NF>
617 constexpr UFix<NI, NF> operator*(float op, const UFix<NI, NF>& uf) {return uf*op;}
618 
619 template <int8_t NI, int8_t NF>
620 constexpr UFix<NI, NF> operator*(double op, const UFix<NI, NF>& uf) {return uf*op;}
621 
622 // Addition
623 template <int8_t NI, int8_t NF>
624 constexpr UFix<NI, NF> operator+(uint8_t op, const UFix<NI, NF>& uf) {return uf+op;}
625 
626 template <int8_t NI, int8_t NF>
627 constexpr UFix<NI, NF> operator+(uint16_t op, const UFix<NI, NF>& uf) {return uf+op;}
628 
629 template <int8_t NI, int8_t NF>
630 constexpr UFix<NI, NF> operator+(uint32_t op, const UFix<NI, NF>& uf) {return uf+op;}
631 
632 template <int8_t NI, int8_t NF>
633 constexpr UFix<NI, NF> operator+(uint64_t op, const UFix<NI, NF>& uf) {return uf+op;}
634 
635 template <int8_t NI, int8_t NF>
636 constexpr UFix<NI, NF> operator+(int8_t op, const UFix<NI, NF>& uf) {return uf+op;}
637 
638 template <int8_t NI, int8_t NF>
639 constexpr UFix<NI, NF> operator+(int16_t op, const UFix<NI, NF>& uf) {return uf+op;}
640 
641 template <int8_t NI, int8_t NF>
642 constexpr UFix<NI, NF> operator+(int32_t op, const UFix<NI, NF>& uf) {return uf+op;}
643 
644 template <int8_t NI, int8_t NF>
645 constexpr UFix<NI, NF> operator+(int64_t op, const UFix<NI, NF>& uf) {return uf+op;}
646 
647 template <int8_t NI, int8_t NF>
648 constexpr UFix<NI, NF> operator+(float op, const UFix<NI, NF>& uf) {return uf+op;}
649 
650 template <int8_t NI, int8_t NF>
651 constexpr UFix<NI, NF> operator+(double op, const UFix<NI, NF>& uf) {return uf+op;}
652 
653 // Substraction
654 template <int8_t NI, int8_t NF>
655 constexpr SFix<NI, NF> operator-(uint8_t op, const UFix<NI, NF>& uf) {return -uf+op;}
656 
657 template <int8_t NI, int8_t NF>
658 constexpr SFix<NI, NF> operator-(uint16_t op, const UFix<NI, NF>& uf) {return -uf+op;}
659 
660 template <int8_t NI, int8_t NF>
661 constexpr SFix<NI, NF> operator-(uint32_t op, const UFix<NI, NF>& uf) {return -uf+op;}
662 
663 template <int8_t NI, int8_t NF>
664 constexpr SFix<NI, NF> operator-(uint64_t op, const UFix<NI, NF>& uf) {return -uf+op;}
665 
666 template <int8_t NI, int8_t NF>
667 constexpr SFix<NI, NF> operator-(int8_t op, const UFix<NI, NF>& uf) {return -uf+op;}
668 
669 template <int8_t NI, int8_t NF>
670 constexpr SFix<NI, NF> operator-(int16_t op, const UFix<NI, NF>& uf) {return -uf+op;}
671 
672 template <int8_t NI, int8_t NF>
673 constexpr SFix<NI, NF> operator-(int32_t op, const UFix<NI, NF>& uf) {return -uf+op;}
674 
675 template <int8_t NI, int8_t NF>
676 constexpr SFix<NI, NF> operator-(int64_t op, const UFix<NI, NF>& uf) {return -uf+op;}
677 
678 template <int8_t NI, int8_t NF>
679 constexpr SFix<NI, NF> operator-(float op, const UFix<NI, NF>& uf) {return -uf+op;}
680 
681 template <int8_t NI, int8_t NF>
682 constexpr SFix<NI, NF> operator-(double op, const UFix<NI, NF>& uf) {return -uf+op;}
683 #endif
685 
686 
702 template<typename T>
703 constexpr inline UFix<0, sizeof(T)*8> toUFraction(T val) {
704  return UFix<0, sizeof(T)*8>::fromRaw(val);
705 }
706 
721 template<typename T>
722 constexpr inline UFix<sizeof(T)*8,0> toUInt(T val) {
723  return UFix<sizeof(T)*8,0>::fromRaw(val);
724 }
725 
738 // TODO: auto sixteen = UFixAuto<16>(); could be made to return UFix<1, -4>!
739 template<uint64_t value>
740 constexpr FixMathPrivate::UFixByRange_t<0, value> UFixAuto() {
741  return FixMathPrivate::UFixByRange_t<0, value>::fromRaw(value);
742 }
743 
744 
745 
752 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.
753 class SFix
754 {
755  static_assert(NI+NF<64, "The total width of a SFix cannot exceed 63bits");
756  typedef typename IntegerType<FixMathPrivate::sBitsToBytes(NI+NF)>::signed_type internal_type ; // smallest size that fits our internal integer
757  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.
758 
759 public:
762  constexpr SFix() {}
763 
768  constexpr SFix(float fl) : internal_value(/*static_cast<internal_type>*/(fl * (next_greater_type(1) << NF))) {}
769 
774  constexpr SFix(double fl) : internal_value(static_cast<internal_type> (fl * (next_greater_type(1) << NF))) {}
775 
776 
783  template<typename T>
784  constexpr SFix(T value,bool as_raw=false) : internal_value(as_raw ? value : (internal_type(value) << NF)) {};
785 
790  template<typename T>
791  static constexpr SFix<NI,NF> fromRaw(T raw){return SFix<NI,NF>(raw,true);}
792 
793 
798  template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
799  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))) {}
800 
805  template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
806  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))) {};
807 
809 
814  template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
815  constexpr FixMathPrivate::SFixByRange_t<FixMathPrivate::FM_max(NF,_NF),FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)> operator+ (const SFix<_NI,_NF,_RANGE>& op) const
816  {
817  typedef FixMathPrivate::SFixByRange_t<FixMathPrivate::FM_max(NF,_NF),FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)> worktype;
818  return worktype(worktype(*this).asRaw() + worktype(op).asRaw(), true);
819  }
820 
826  template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
827  constexpr FixMathPrivate::SFixByRange_t<FixMathPrivate::FM_max(NF,_NF),FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)> operator+ (const UFix<_NI,_NF,_RANGE>& op2) const
828  {
829  return op2+(*this);
830  }
831 
832 #ifdef FIXMATH_UNSAFE
838  template<typename T>
839  constexpr SFix<NI,NF> operator+ (const T op) const
840  {
841  return SFix<NI,NF>(internal_value+(op<<NF),true);
842  }
843 #endif
844 
846 
851  template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
852  constexpr FixMathPrivate::SFixByRange_t<FixMathPrivate::FM_max(NF,_NF),FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)> operator- (const SFix<_NI,_NF, _RANGE>& op) const
853  {
854  typedef FixMathPrivate::SFixByRange_t<FixMathPrivate::FM_max(NF,_NF),FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)> worktype;
855  return worktype(worktype(*this).asRaw() - worktype(op).asRaw(), true);
856  }
857 
862  template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
863  constexpr FixMathPrivate::SFixByRange_t<FixMathPrivate::FM_max(NF,_NF),FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)> operator- (const UFix<_NI,_NF, _RANGE>& op) const
864  {
865  typedef FixMathPrivate::SFixByRange_t<FixMathPrivate::FM_max(NF,_NF),FixMathPrivate::rangeAdd(NF,_NF,RANGE,_RANGE)> worktype;
866  return worktype(worktype(*this).asRaw() - worktype(op).asRaw(), true);
867  }
868 
869 #ifdef FIXMATH_UNSAFE
875  template<typename T>
876  constexpr SFix<NI,NF> operator- (const T op) const
877  {
878  return SFix<NI,NF>(internal_value-(op<<NF),true);
879  }
880 #endif
881 
885  /* constexpr SFix<NI,NF,RANGE> operator-() const
886  {
887  return SFix<NI,NF,RANGE>(-internal_value,true);
888  }*/
889  constexpr FixMathPrivate::SFixByRange_t<NF,RANGE+1> operator-() const
890  {
891 typedef FixMathPrivate::SFixByRange_t<NF, RANGE+1> returntype;
892  return returntype(-internal_value,true);
893  }
894 
896 
901  template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
902  constexpr FixMathPrivate::SFixByRange_t<NF+_NF, RANGE*_RANGE> operator* (const SFix<_NI,_NF,_RANGE>& op) const
903  {
904  typedef FixMathPrivate::SFixByRange_t<NF+_NF, RANGE*_RANGE> worktype;
905  return worktype((typename worktype::internal_type)(internal_value)*op.asRaw(), true);
906  }
907 
913  template<int8_t _NI, int8_t _NF, uint64_t _RANGE>
914  constexpr FixMathPrivate::SFixByRange_t<NF+_NF, RANGE*_RANGE> operator* (const UFix<_NI,_NF,_RANGE>& op2) const
915  {
916  return op2*(*this);
917  }
918 
919 #ifdef FIXMATH_UNSAFE
925  template<typename T>
926  constexpr SFix<NI,NF> operator* (const T op) const
927  {
928  return SFix<NI,NF>(internal_value*op,true);
929  }
930 #endif
931 
932 
934 
942  constexpr SFix<NF,NI> invFast() const
943  {
944  static_assert(NI+NF<=63, "The fast inverse cannot be computed for when NI+NF>63. Reduce the number of bits.");
945  return SFix<NF,NI>((onesbitmask()/internal_value),true);
946  }
947 
952  template<int8_t _NF>
953  constexpr SFix<NF,_NF> inv() const
954  {
955  return SFix<_NF,NF>(internal_value,true).invFast();
956  }
957 
963  constexpr SFix<NF,FixMathPrivate::FM_min(NI*2+NF,63-NF)> invFull() const
964  {
965  return inv<NI*2+NF>();
966  }
967 
968 
977  template<int8_t _NF=FixMathPrivate::FM_min(NI*2+NF-1,63-NF)>
978  constexpr SFix<NF,_NF> invAccurate() const
979  {
980  static_assert(NF+_NF+1<=63, "The accurate inverse cannot be computed because the asked precision is too great. Reduce the number of bits.");
981  return SFix<NF,_NF>(SFix<NF,_NF+1>::msbone()/internal_value,true);
982  }
983 
984 
986 
992  constexpr SFix<NI,NF> operator>> (const int8_t op) const
993  {
994  return SFix<NI,NF>(internal_value>>op,true);
995  }
996 
997 #ifdef FIXMATH_UNSAFE
1004  constexpr SFix<NI,NF> operator<< (const int8_t op) const
1005  {
1006  return SFix<NI,NF>(internal_value<<op,true);
1007  }
1008 #endif
1009 
1014  template<int8_t op>
1015  constexpr SFix<FixMathPrivate::FM_max(NI-op,0), NF+op, FixMathPrivate::rangeShift(NI,op,RANGE)> sR()
1016  {
1017  return SFix<FixMathPrivate::FM_max(NI-op,0),NF+op,FixMathPrivate::rangeShift(NI,op,RANGE)>(internal_value,true);
1018  }
1019 
1024  template<int8_t op>
1025  constexpr SFix<NI+op,FixMathPrivate::FM_max(NF-op,0),FixMathPrivate::rangeShift(NF,op,RANGE)> sL()
1026  {
1027  return SFix<NI+op,FixMathPrivate::FM_max(NF-op,0)>(internal_value,true);
1028  }
1029 
1030 
1032 
1037  template<int8_t _NI, int8_t _NF>
1038  constexpr bool operator> (const SFix<_NI,_NF>& op) const
1039  {
1040  using namespace FixMathPrivate;
1041  typedef SFix<FM_max(NI, _NI), FM_max(NF, _NF)> comptype; // common type suitable for comparison
1042  return comptype(*this).asRaw()>comptype(op).asRaw();
1043  }
1044 
1049  template<int8_t _NI, int8_t _NF>
1050  constexpr bool operator< (const SFix<_NI,_NF>& op) const
1051  {
1052  return op > *this;
1053  }
1054 
1055 
1060  template<int8_t _NI, int8_t _NF>
1061  constexpr bool operator== (const SFix<_NI,_NF>& op) const
1062  {
1063  using namespace FixMathPrivate;
1064  typedef SFix<FM_max(NI, _NI), FM_max(NF, _NF)> comptype; // common type suitable for comparison
1065  return comptype(*this).asRaw()==comptype(op).asRaw();
1066  }
1067 
1072  template<int8_t _NI, int8_t _NF>
1073  constexpr bool operator!= (const SFix<_NI,_NF>& op) const
1074  {
1075  typedef SFix<FixMathPrivate::FM_max(NI, _NI), FixMathPrivate::FM_max(NF, _NF)> comptype; // common type suitable for comparison
1076  return comptype(*this).asRaw()!=comptype(op).asRaw();
1077  }
1078 
1079 
1083  constexpr UFix<NI,NF,RANGE> asUFix() const
1084  {
1085  return UFix<NI,NF,RANGE>(internal_value,true);
1086  }
1087 
1088 
1092  constexpr float asFloat() const {return (static_cast<float>(internal_value)) / (next_greater_type(1)<<NF); }
1093 
1098  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.
1099  {
1100  SFix<NI+1,0> integer_part(*this);
1101  return integer_part.asRaw();
1102  }
1103 
1107  constexpr internal_type asRaw() const {return internal_value; }
1108 
1112  static constexpr int8_t getNI() {return NI;}
1113 
1117  static constexpr int8_t getNF() {return NF;}
1118 
1122  static constexpr int8_t getRANGE() {return RANGE;}
1123 
1124 
1130  template<int8_t BITS> static constexpr void assertSize() { static_assert(NI+NF+1 <= BITS, "Data type is larger than expected!"); }
1131 private:
1132  template<int8_t, int8_t, uint64_t> friend class UFix; // for access to internal_type
1133  template<int8_t, int8_t, uint64_t> friend class SFix;
1134 
1135  internal_type internal_value;
1136  //static constexpr internal_type onesbitmask() { return (internal_type) ((1ULL<< (NI+NF)) - 1); }
1137  static constexpr internal_type onesbitmask() { return (internal_type) ((1ULL<< (NI+NF-1)) + ((1ULL<< (NI+NF-1)) - 1)); }
1138  static constexpr internal_type msbone() { return (internal_type) (1ULL<< (NI+NF-1)); }
1139 };
1140 
1141 
1142 #ifdef FIXMATH_UNSAFE
1144 
1145 // Multiplication
1146 template <int8_t NI, int8_t NF>
1147 constexpr SFix<NI, NF> operator*(uint8_t op, const SFix<NI, NF>& uf) {return uf*op;}
1148 
1149 template <int8_t NI, int8_t NF>
1150 constexpr SFix<NI, NF> operator*(uint16_t op, const SFix<NI, NF>& uf) {return uf*op;}
1151 
1152 template <int8_t NI, int8_t NF>
1153 constexpr SFix<NI, NF> operator*(uint32_t op, const SFix<NI, NF>& uf) {return uf*op;}
1154 
1155 template <int8_t NI, int8_t NF>
1156 constexpr SFix<NI, NF> operator*(uint64_t op, const SFix<NI, NF>& uf) {return uf*op;}
1157 
1158 template <int8_t NI, int8_t NF>
1159 constexpr SFix<NI, NF> operator*(int8_t op, const SFix<NI, NF>& uf) {return uf*op;}
1160 
1161 template <int8_t NI, int8_t NF>
1162 constexpr SFix<NI, NF> operator*(int16_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*(int32_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*(int64_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*(float op, const SFix<NI, NF>& uf) {return uf*op;}
1172 
1173 template <int8_t NI, int8_t NF>
1174 constexpr SFix<NI, NF> operator*(double op, const SFix<NI, NF>& uf) {return uf*op;}
1175 
1176 // Addition
1177 template <int8_t NI, int8_t NF>
1178 constexpr SFix<NI, NF> operator+(uint8_t op, const SFix<NI, NF>& uf) {return uf+op;}
1179 
1180 template <int8_t NI, int8_t NF>
1181 constexpr SFix<NI, NF> operator+(uint16_t op, const SFix<NI, NF>& uf) {return uf+op;}
1182 
1183 template <int8_t NI, int8_t NF>
1184 constexpr SFix<NI, NF> operator+(uint32_t op, const SFix<NI, NF>& uf) {return uf+op;}
1185 
1186 template <int8_t NI, int8_t NF>
1187 constexpr SFix<NI, NF> operator+(uint64_t op, const SFix<NI, NF>& uf) {return uf+op;}
1188 
1189 template <int8_t NI, int8_t NF>
1190 constexpr SFix<NI, NF> operator+(int8_t op, const SFix<NI, NF>& uf) {return uf+op;}
1191 
1192 template <int8_t NI, int8_t NF>
1193 constexpr SFix<NI, NF> operator+(int16_t op, const SFix<NI, NF>& uf) {return uf+op;}
1194 
1195 template <int8_t NI, int8_t NF>
1196 constexpr SFix<NI, NF> operator+(int32_t op, const SFix<NI, NF>& uf) {return uf+op;}
1197 
1198 template <int8_t NI, int8_t NF>
1199 constexpr SFix<NI, NF> operator+(int64_t op, const SFix<NI, NF>& uf) {return uf+op;}
1200 
1201 template <int8_t NI, int8_t NF>
1202 constexpr SFix<NI, NF> operator+(float op, const SFix<NI, NF>& uf) {return uf+op;}
1203 
1204 template <int8_t NI, int8_t NF>
1205 constexpr SFix<NI, NF> operator+(double op, const SFix<NI, NF>& uf) {return uf+op;}
1206 
1207 // Substraction
1208 template <int8_t NI, int8_t NF>
1209 constexpr SFix<NI, NF> operator-(uint8_t op, const SFix<NI, NF>& uf) {return (-uf)+op;}
1210 
1211 template <int8_t NI, int8_t NF>
1212 constexpr SFix<NI, NF> operator-(uint16_t op, const SFix<NI, NF>& uf) {return (-uf)+op;}
1213 
1214 template <int8_t NI, int8_t NF>
1215 constexpr SFix<NI, NF> operator-(uint32_t op, const SFix<NI, NF>& uf) {return (-uf)+op;}
1216 
1217 template <int8_t NI, int8_t NF>
1218 constexpr SFix<NI, NF> operator-(uint64_t op, const SFix<NI, NF>& uf) {return (-uf)+op;}
1219 
1220 template <int8_t NI, int8_t NF>
1221 constexpr SFix<NI, NF> operator-(int8_t op, const SFix<NI, NF>& uf) {return (-uf)+op;}
1222 
1223 template <int8_t NI, int8_t NF>
1224 constexpr SFix<NI, NF> operator-(int16_t op, const SFix<NI, NF>& uf) {return (-uf)+op;}
1225 
1226 template <int8_t NI, int8_t NF>
1227 constexpr SFix<NI, NF> operator-(int32_t op, const SFix<NI, NF>& uf) {return (-uf)+op;}
1228 
1229 template <int8_t NI, int8_t NF>
1230 constexpr SFix<NI, NF> operator-(int64_t op, const SFix<NI, NF>& uf) {return (-uf)+op;}
1231 
1232 template <int8_t NI, int8_t NF>
1233 constexpr SFix<NI, NF> operator-(float op, const SFix<NI, NF>& uf) {return (-uf)+op;}
1234 
1235 template <int8_t NI, int8_t NF>
1236 constexpr SFix<NI, NF> operator-(double op, const SFix<NI, NF>& uf) {return (-uf)+op;}
1237 
1238 #endif
1239 
1240 
1241 
1242 
1243 
1244 // Comparison between SFix and UFix
1245 
1251 template<int8_t NI, int8_t NF, int8_t _NI, int8_t _NF>
1252 constexpr bool operator> (const SFix<NI,NF>& op1, const UFix<_NI,_NF>& op2 )
1253 {
1254  typedef SFix<FixMathPrivate::FM_max(NI, _NI), FixMathPrivate::FM_max(NF, _NF)> worktype;
1255  return worktype(op1).asRaw() > worktype(op2).asRaw();
1256 }
1257 
1263 template<int8_t NI, int8_t NF, int8_t _NI, int8_t _NF>
1264 constexpr bool operator> (const UFix<NI,NF>& op1, const SFix<_NI,_NF>& op2 )
1265 {
1266  typedef SFix<FixMathPrivate::FM_max(NI, _NI), FixMathPrivate::FM_max(NF, _NF)> worktype;
1267  return worktype(op1).asRaw() > worktype(op2).asRaw();
1268 }
1269 
1275 template<int8_t NI, int8_t NF, int8_t _NI, int8_t _NF>
1276 constexpr bool operator< (const UFix<NI,NF>& op1, const SFix<_NI,_NF>& op2 )
1277 {
1278  return op2 > op1;
1279 }
1280 
1281 
1287 template<int8_t NI, int8_t NF, int8_t _NI, int8_t _NF>
1288 constexpr bool operator< (const SFix<NI,NF>& op1, const UFix<_NI,_NF>& op2 )
1289 {
1290  return op2 > op1;
1291 }
1292 
1293 
1299 template<int8_t NI, int8_t NF, int8_t _NI, int8_t _NF>
1300 constexpr bool operator== (const SFix<NI,NF>& op1, const UFix<_NI,_NF>& op2)
1301 {
1302  typedef SFix<FixMathPrivate::FM_max(NI, _NI), FixMathPrivate::FM_max(NF, _NF)> worktype;
1303  return (worktype(op1).asRaw() == worktype(op2).asRaw());
1304 }
1305 
1306 
1312 template<int8_t NI, int8_t NF, int8_t _NI, int8_t _NF>
1313 constexpr bool operator== (const UFix<NI,NF>& op1, const SFix<_NI,_NF>& op2 )
1314 {
1315  return op2 == op1;
1316 }
1317 
1323 template<int8_t NI, int8_t NF, int8_t _NI, int8_t _NF>
1324 constexpr bool operator!= (const SFix<NI,NF>& op1, const UFix<_NI,_NF>& op2 )
1325 {
1326  return !(op1 == op2);
1327 }
1328 
1329 
1335 template<int8_t NI, int8_t NF, int8_t _NI, int8_t _NF>
1336 constexpr bool operator!= (const UFix<NI,NF>& op1, const SFix<_NI,_NF>& op2 )
1337 {
1338  typedef SFix<FixMathPrivate::FM_max(NI, _NI), FixMathPrivate::FM_max(NF, _NF)> comptype;
1339  return (comptype(op1).asRaw() != comptype(op2).asRaw());;
1340 }
1341 
1343 
1344 
1360 template<typename T>
1361 constexpr SFix<0, sizeof(T)*8-1> toSFraction(T val) {
1362  return SFix<0, sizeof(T)*8-1>::fromRaw(val);
1363 }
1364 
1379 template<typename T>
1380 constexpr SFix<sizeof(T)*8-1,0> toSInt(T val) {
1381  return SFix<sizeof(T)*8-1,0>::fromRaw(val);
1382 }
1383 
1396 template<int64_t value>
1397 constexpr const FixMathPrivate::SFixByRange_t<0, value < 0 ? -value : value+1> SFixAuto() {
1398  return FixMathPrivate::SFixByRange_t<0, value < 0 ? -value : value+1>::fromRaw(value);
1399 }
1400 
1401 #include "FixMath_Autotests.h"
1402 
1403 
1404 #endif
Definition: FixMath.h:754
constexpr internal_type asRaw() const
Definition: FixMath.h:1107
Definition: FixMath.h:170
constexpr SFix< NI, NF, RANGE > operator-() const
Definition: FixMath.h:314
constexpr internal_type asRaw() const
Definition: FixMath.h:545
constexpr UFix(float fl)
Definition: FixMath.h:184
constexpr UFix(double fl)
Definition: FixMath.h:190
constexpr UFix(T value, bool as_raw=false)
Definition: FixMath.h:201
constexpr UFix()
Definition: FixMath.h:178
constexpr UFix< NF, NI > invFast() const
Definition: FixMath.h:364
constexpr FixMathPrivate::UFixByRange_t< NF+_NF, RANGE *_RANGE > operator*(const UFix< _NI, _NF, _RANGE > &op) const
Definition: FixMath.h:326
static constexpr UFix< NI, NF > fromRaw(T raw)
Definition: FixMath.h:209
constexpr UFix(const UFix< _NI, _NF, _RANGE > &uf)
Definition: FixMath.h:220
constexpr FixMathPrivate::UFixByRange_t< FixMathPrivate::FM_max(NF, _NF), FixMathPrivate::rangeAdd(NF, _NF, RANGE, _RANGE)> operator+(const UFix< _NI, _NF, _RANGE > &op) const
Definition: FixMath.h:239
constexpr UFix(const SFix< _NI, _NF, _RANGE > &uf)
Definition: FixMath.h:229
Definition: FixMath.h:126
Definition: FixMath.h:138
Definition: IntegerType.h:9