fixed_point.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. // SPDX-FileCopyrightText: 2015 Evan Teran
  2. // SPDX-License-Identifier: MIT
  3. // From: https://github.com/eteran/cpp-utilities/blob/master/fixed/include/cpp-utilities/fixed.h
  4. // See also: http://stackoverflow.com/questions/79677/whats-the-best-way-to-do-fixed-point-math
  5. #pragma once
  6. #if __cplusplus >= 201402L
  7. #define CONSTEXPR14 constexpr
  8. #else
  9. #define CONSTEXPR14
  10. #endif
  11. #include <cstddef> // for size_t
  12. #include <cstdint>
  13. #include <exception>
  14. #include <ostream>
  15. #include <type_traits>
  16. namespace Common {
  17. template <size_t I, size_t F>
  18. class FixedPoint;
  19. namespace detail {
  20. // helper templates to make magic with types :)
  21. // these allow us to determine resonable types from
  22. // a desired size, they also let us infer the next largest type
  23. // from a type which is nice for the division op
  24. template <size_t T>
  25. struct type_from_size {
  26. using value_type = void;
  27. using unsigned_type = void;
  28. using signed_type = void;
  29. static constexpr bool is_specialized = false;
  30. };
  31. #if defined(__GNUC__) && defined(__x86_64__) && !defined(__STRICT_ANSI__)
  32. template <>
  33. struct type_from_size<128> {
  34. static constexpr bool is_specialized = true;
  35. static constexpr size_t size = 128;
  36. using value_type = __int128;
  37. using unsigned_type = unsigned __int128;
  38. using signed_type = __int128;
  39. using next_size = type_from_size<256>;
  40. };
  41. #endif
  42. template <>
  43. struct type_from_size<64> {
  44. static constexpr bool is_specialized = true;
  45. static constexpr size_t size = 64;
  46. using value_type = int64_t;
  47. using unsigned_type = std::make_unsigned<value_type>::type;
  48. using signed_type = std::make_signed<value_type>::type;
  49. using next_size = type_from_size<128>;
  50. };
  51. template <>
  52. struct type_from_size<32> {
  53. static constexpr bool is_specialized = true;
  54. static constexpr size_t size = 32;
  55. using value_type = int32_t;
  56. using unsigned_type = std::make_unsigned<value_type>::type;
  57. using signed_type = std::make_signed<value_type>::type;
  58. using next_size = type_from_size<64>;
  59. };
  60. template <>
  61. struct type_from_size<16> {
  62. static constexpr bool is_specialized = true;
  63. static constexpr size_t size = 16;
  64. using value_type = int16_t;
  65. using unsigned_type = std::make_unsigned<value_type>::type;
  66. using signed_type = std::make_signed<value_type>::type;
  67. using next_size = type_from_size<32>;
  68. };
  69. template <>
  70. struct type_from_size<8> {
  71. static constexpr bool is_specialized = true;
  72. static constexpr size_t size = 8;
  73. using value_type = int8_t;
  74. using unsigned_type = std::make_unsigned<value_type>::type;
  75. using signed_type = std::make_signed<value_type>::type;
  76. using next_size = type_from_size<16>;
  77. };
  78. // this is to assist in adding support for non-native base
  79. // types (for adding big-int support), this should be fine
  80. // unless your bit-int class doesn't nicely support casting
  81. template <class B, class N>
  82. constexpr B next_to_base(N rhs) {
  83. return static_cast<B>(rhs);
  84. }
  85. struct divide_by_zero : std::exception {};
  86. template <size_t I, size_t F>
  87. CONSTEXPR14 FixedPoint<I, F> divide(
  88. FixedPoint<I, F> numerator, FixedPoint<I, F> denominator, FixedPoint<I, F>& remainder,
  89. typename std::enable_if<type_from_size<I + F>::next_size::is_specialized>::type* = nullptr) {
  90. using next_type = typename FixedPoint<I, F>::next_type;
  91. using base_type = typename FixedPoint<I, F>::base_type;
  92. constexpr size_t fractional_bits = FixedPoint<I, F>::fractional_bits;
  93. next_type t(numerator.to_raw());
  94. t <<= fractional_bits;
  95. FixedPoint<I, F> quotient;
  96. quotient = FixedPoint<I, F>::from_base(next_to_base<base_type>(t / denominator.to_raw()));
  97. remainder = FixedPoint<I, F>::from_base(next_to_base<base_type>(t % denominator.to_raw()));
  98. return quotient;
  99. }
  100. template <size_t I, size_t F>
  101. CONSTEXPR14 FixedPoint<I, F> divide(
  102. FixedPoint<I, F> numerator, FixedPoint<I, F> denominator, FixedPoint<I, F>& remainder,
  103. typename std::enable_if<!type_from_size<I + F>::next_size::is_specialized>::type* = nullptr) {
  104. using unsigned_type = typename FixedPoint<I, F>::unsigned_type;
  105. constexpr int bits = FixedPoint<I, F>::total_bits;
  106. if (denominator == 0) {
  107. throw divide_by_zero();
  108. } else {
  109. int sign = 0;
  110. FixedPoint<I, F> quotient;
  111. if (numerator < 0) {
  112. sign ^= 1;
  113. numerator = -numerator;
  114. }
  115. if (denominator < 0) {
  116. sign ^= 1;
  117. denominator = -denominator;
  118. }
  119. unsigned_type n = numerator.to_raw();
  120. unsigned_type d = denominator.to_raw();
  121. unsigned_type x = 1;
  122. unsigned_type answer = 0;
  123. // egyptian division algorithm
  124. while ((n >= d) && (((d >> (bits - 1)) & 1) == 0)) {
  125. x <<= 1;
  126. d <<= 1;
  127. }
  128. while (x != 0) {
  129. if (n >= d) {
  130. n -= d;
  131. answer += x;
  132. }
  133. x >>= 1;
  134. d >>= 1;
  135. }
  136. unsigned_type l1 = n;
  137. unsigned_type l2 = denominator.to_raw();
  138. // calculate the lower bits (needs to be unsigned)
  139. while (l1 >> (bits - F) > 0) {
  140. l1 >>= 1;
  141. l2 >>= 1;
  142. }
  143. const unsigned_type lo = (l1 << F) / l2;
  144. quotient = FixedPoint<I, F>::from_base((answer << F) | lo);
  145. remainder = n;
  146. if (sign) {
  147. quotient = -quotient;
  148. }
  149. return quotient;
  150. }
  151. }
  152. // this is the usual implementation of multiplication
  153. template <size_t I, size_t F>
  154. CONSTEXPR14 FixedPoint<I, F> multiply(
  155. FixedPoint<I, F> lhs, FixedPoint<I, F> rhs,
  156. typename std::enable_if<type_from_size<I + F>::next_size::is_specialized>::type* = nullptr) {
  157. using next_type = typename FixedPoint<I, F>::next_type;
  158. using base_type = typename FixedPoint<I, F>::base_type;
  159. constexpr size_t fractional_bits = FixedPoint<I, F>::fractional_bits;
  160. next_type t(static_cast<next_type>(lhs.to_raw()) * static_cast<next_type>(rhs.to_raw()));
  161. t >>= fractional_bits;
  162. return FixedPoint<I, F>::from_base(next_to_base<base_type>(t));
  163. }
  164. // this is the fall back version we use when we don't have a next size
  165. // it is slightly slower, but is more robust since it doesn't
  166. // require and upgraded type
  167. template <size_t I, size_t F>
  168. CONSTEXPR14 FixedPoint<I, F> multiply(
  169. FixedPoint<I, F> lhs, FixedPoint<I, F> rhs,
  170. typename std::enable_if<!type_from_size<I + F>::next_size::is_specialized>::type* = nullptr) {
  171. using base_type = typename FixedPoint<I, F>::base_type;
  172. constexpr size_t fractional_bits = FixedPoint<I, F>::fractional_bits;
  173. constexpr base_type integer_mask = FixedPoint<I, F>::integer_mask;
  174. constexpr base_type fractional_mask = FixedPoint<I, F>::fractional_mask;
  175. // more costly but doesn't need a larger type
  176. const base_type a_hi = (lhs.to_raw() & integer_mask) >> fractional_bits;
  177. const base_type b_hi = (rhs.to_raw() & integer_mask) >> fractional_bits;
  178. const base_type a_lo = (lhs.to_raw() & fractional_mask);
  179. const base_type b_lo = (rhs.to_raw() & fractional_mask);
  180. const base_type x1 = a_hi * b_hi;
  181. const base_type x2 = a_hi * b_lo;
  182. const base_type x3 = a_lo * b_hi;
  183. const base_type x4 = a_lo * b_lo;
  184. return FixedPoint<I, F>::from_base((x1 << fractional_bits) + (x3 + x2) +
  185. (x4 >> fractional_bits));
  186. }
  187. } // namespace detail
  188. template <size_t I, size_t F>
  189. class FixedPoint {
  190. static_assert(detail::type_from_size<I + F>::is_specialized, "invalid combination of sizes");
  191. public:
  192. static constexpr size_t fractional_bits = F;
  193. static constexpr size_t integer_bits = I;
  194. static constexpr size_t total_bits = I + F;
  195. using base_type_info = detail::type_from_size<total_bits>;
  196. using base_type = typename base_type_info::value_type;
  197. using next_type = typename base_type_info::next_size::value_type;
  198. using unsigned_type = typename base_type_info::unsigned_type;
  199. public:
  200. #ifdef __GNUC__
  201. #pragma GCC diagnostic push
  202. #pragma GCC diagnostic ignored "-Woverflow"
  203. #endif
  204. static constexpr base_type fractional_mask =
  205. ~(static_cast<unsigned_type>(~base_type(0)) << fractional_bits);
  206. static constexpr base_type integer_mask = ~fractional_mask;
  207. #ifdef __GNUC__
  208. #pragma GCC diagnostic pop
  209. #endif
  210. public:
  211. static constexpr base_type one = base_type(1) << fractional_bits;
  212. public: // constructors
  213. FixedPoint() = default;
  214. FixedPoint(const FixedPoint&) = default;
  215. FixedPoint(FixedPoint&&) = default;
  216. FixedPoint& operator=(const FixedPoint&) = default;
  217. template <class Number>
  218. constexpr FixedPoint(
  219. Number n, typename std::enable_if<std::is_arithmetic<Number>::value>::type* = nullptr)
  220. : data_(static_cast<base_type>(n * one)) {}
  221. public: // conversion
  222. template <size_t I2, size_t F2>
  223. CONSTEXPR14 explicit FixedPoint(FixedPoint<I2, F2> other) {
  224. static_assert(I2 <= I && F2 <= F, "Scaling conversion can only upgrade types");
  225. using T = FixedPoint<I2, F2>;
  226. const base_type fractional = (other.data_ & T::fractional_mask);
  227. const base_type integer = (other.data_ & T::integer_mask) >> T::fractional_bits;
  228. data_ =
  229. (integer << fractional_bits) | (fractional << (fractional_bits - T::fractional_bits));
  230. }
  231. private:
  232. // this makes it simpler to create a FixedPoint point object from
  233. // a native type without scaling
  234. // use "FixedPoint::from_base" in order to perform this.
  235. struct NoScale {};
  236. constexpr FixedPoint(base_type n, const NoScale&) : data_(n) {}
  237. public:
  238. static constexpr FixedPoint from_base(base_type n) {
  239. return FixedPoint(n, NoScale());
  240. }
  241. public: // comparison operators
  242. constexpr bool operator==(FixedPoint rhs) const {
  243. return data_ == rhs.data_;
  244. }
  245. constexpr bool operator!=(FixedPoint rhs) const {
  246. return data_ != rhs.data_;
  247. }
  248. constexpr bool operator<(FixedPoint rhs) const {
  249. return data_ < rhs.data_;
  250. }
  251. constexpr bool operator>(FixedPoint rhs) const {
  252. return data_ > rhs.data_;
  253. }
  254. constexpr bool operator<=(FixedPoint rhs) const {
  255. return data_ <= rhs.data_;
  256. }
  257. constexpr bool operator>=(FixedPoint rhs) const {
  258. return data_ >= rhs.data_;
  259. }
  260. public: // unary operators
  261. constexpr bool operator!() const {
  262. return !data_;
  263. }
  264. constexpr FixedPoint operator~() const {
  265. // NOTE(eteran): this will often appear to "just negate" the value
  266. // that is not an error, it is because -x == (~x+1)
  267. // and that "+1" is adding an infinitesimally small fraction to the
  268. // complimented value
  269. return FixedPoint::from_base(~data_);
  270. }
  271. constexpr FixedPoint operator-() const {
  272. return FixedPoint::from_base(-data_);
  273. }
  274. constexpr FixedPoint operator+() const {
  275. return FixedPoint::from_base(+data_);
  276. }
  277. CONSTEXPR14 FixedPoint& operator++() {
  278. data_ += one;
  279. return *this;
  280. }
  281. CONSTEXPR14 FixedPoint& operator--() {
  282. data_ -= one;
  283. return *this;
  284. }
  285. CONSTEXPR14 FixedPoint operator++(int) {
  286. FixedPoint tmp(*this);
  287. data_ += one;
  288. return tmp;
  289. }
  290. CONSTEXPR14 FixedPoint operator--(int) {
  291. FixedPoint tmp(*this);
  292. data_ -= one;
  293. return tmp;
  294. }
  295. public: // basic math operators
  296. CONSTEXPR14 FixedPoint& operator+=(FixedPoint n) {
  297. data_ += n.data_;
  298. return *this;
  299. }
  300. CONSTEXPR14 FixedPoint& operator-=(FixedPoint n) {
  301. data_ -= n.data_;
  302. return *this;
  303. }
  304. CONSTEXPR14 FixedPoint& operator*=(FixedPoint n) {
  305. return assign(detail::multiply(*this, n));
  306. }
  307. CONSTEXPR14 FixedPoint& operator/=(FixedPoint n) {
  308. FixedPoint temp;
  309. return assign(detail::divide(*this, n, temp));
  310. }
  311. private:
  312. CONSTEXPR14 FixedPoint& assign(FixedPoint rhs) {
  313. data_ = rhs.data_;
  314. return *this;
  315. }
  316. public: // binary math operators, effects underlying bit pattern since these
  317. // don't really typically make sense for non-integer values
  318. CONSTEXPR14 FixedPoint& operator&=(FixedPoint n) {
  319. data_ &= n.data_;
  320. return *this;
  321. }
  322. CONSTEXPR14 FixedPoint& operator|=(FixedPoint n) {
  323. data_ |= n.data_;
  324. return *this;
  325. }
  326. CONSTEXPR14 FixedPoint& operator^=(FixedPoint n) {
  327. data_ ^= n.data_;
  328. return *this;
  329. }
  330. template <class Integer,
  331. class = typename std::enable_if<std::is_integral<Integer>::value>::type>
  332. CONSTEXPR14 FixedPoint& operator>>=(Integer n) {
  333. data_ >>= n;
  334. return *this;
  335. }
  336. template <class Integer,
  337. class = typename std::enable_if<std::is_integral<Integer>::value>::type>
  338. CONSTEXPR14 FixedPoint& operator<<=(Integer n) {
  339. data_ <<= n;
  340. return *this;
  341. }
  342. public: // conversion to basic types
  343. constexpr void round_up() {
  344. data_ += (data_ & fractional_mask) >> 1;
  345. }
  346. constexpr int to_int() {
  347. round_up();
  348. return static_cast<int>((data_ & integer_mask) >> fractional_bits);
  349. }
  350. constexpr unsigned int to_uint() const {
  351. round_up();
  352. return static_cast<unsigned int>((data_ & integer_mask) >> fractional_bits);
  353. }
  354. constexpr int64_t to_long() {
  355. round_up();
  356. return static_cast<int64_t>((data_ & integer_mask) >> fractional_bits);
  357. }
  358. constexpr int to_int_floor() const {
  359. return static_cast<int>((data_ & integer_mask) >> fractional_bits);
  360. }
  361. constexpr int64_t to_long_floor() {
  362. return static_cast<int64_t>((data_ & integer_mask) >> fractional_bits);
  363. }
  364. constexpr unsigned int to_uint_floor() const {
  365. return static_cast<unsigned int>((data_ & integer_mask) >> fractional_bits);
  366. }
  367. constexpr float to_float() const {
  368. return static_cast<float>(data_) / FixedPoint::one;
  369. }
  370. constexpr double to_double() const {
  371. return static_cast<double>(data_) / FixedPoint::one;
  372. }
  373. constexpr base_type to_raw() const {
  374. return data_;
  375. }
  376. constexpr void clear_int() {
  377. data_ &= fractional_mask;
  378. }
  379. constexpr base_type get_frac() const {
  380. return data_ & fractional_mask;
  381. }
  382. public:
  383. CONSTEXPR14 void swap(FixedPoint& rhs) {
  384. using std::swap;
  385. swap(data_, rhs.data_);
  386. }
  387. public:
  388. base_type data_;
  389. };
  390. // if we have the same fractional portion, but differing integer portions, we trivially upgrade the
  391. // smaller type
  392. template <size_t I1, size_t I2, size_t F>
  393. CONSTEXPR14 typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type
  394. operator+(FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) {
  395. using T = typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type;
  396. const T l = T::from_base(lhs.to_raw());
  397. const T r = T::from_base(rhs.to_raw());
  398. return l + r;
  399. }
  400. template <size_t I1, size_t I2, size_t F>
  401. CONSTEXPR14 typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type
  402. operator-(FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) {
  403. using T = typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type;
  404. const T l = T::from_base(lhs.to_raw());
  405. const T r = T::from_base(rhs.to_raw());
  406. return l - r;
  407. }
  408. template <size_t I1, size_t I2, size_t F>
  409. CONSTEXPR14 typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type
  410. operator*(FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) {
  411. using T = typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type;
  412. const T l = T::from_base(lhs.to_raw());
  413. const T r = T::from_base(rhs.to_raw());
  414. return l * r;
  415. }
  416. template <size_t I1, size_t I2, size_t F>
  417. CONSTEXPR14 typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type
  418. operator/(FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) {
  419. using T = typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type;
  420. const T l = T::from_base(lhs.to_raw());
  421. const T r = T::from_base(rhs.to_raw());
  422. return l / r;
  423. }
  424. template <size_t I, size_t F>
  425. std::ostream& operator<<(std::ostream& os, FixedPoint<I, F> f) {
  426. os << f.to_double();
  427. return os;
  428. }
  429. // basic math operators
  430. template <size_t I, size_t F>
  431. CONSTEXPR14 FixedPoint<I, F> operator+(FixedPoint<I, F> lhs, FixedPoint<I, F> rhs) {
  432. lhs += rhs;
  433. return lhs;
  434. }
  435. template <size_t I, size_t F>
  436. CONSTEXPR14 FixedPoint<I, F> operator-(FixedPoint<I, F> lhs, FixedPoint<I, F> rhs) {
  437. lhs -= rhs;
  438. return lhs;
  439. }
  440. template <size_t I, size_t F>
  441. CONSTEXPR14 FixedPoint<I, F> operator*(FixedPoint<I, F> lhs, FixedPoint<I, F> rhs) {
  442. lhs *= rhs;
  443. return lhs;
  444. }
  445. template <size_t I, size_t F>
  446. CONSTEXPR14 FixedPoint<I, F> operator/(FixedPoint<I, F> lhs, FixedPoint<I, F> rhs) {
  447. lhs /= rhs;
  448. return lhs;
  449. }
  450. template <size_t I, size_t F, class Number,
  451. class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
  452. CONSTEXPR14 FixedPoint<I, F> operator+(FixedPoint<I, F> lhs, Number rhs) {
  453. lhs += FixedPoint<I, F>(rhs);
  454. return lhs;
  455. }
  456. template <size_t I, size_t F, class Number,
  457. class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
  458. CONSTEXPR14 FixedPoint<I, F> operator-(FixedPoint<I, F> lhs, Number rhs) {
  459. lhs -= FixedPoint<I, F>(rhs);
  460. return lhs;
  461. }
  462. template <size_t I, size_t F, class Number,
  463. class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
  464. CONSTEXPR14 FixedPoint<I, F> operator*(FixedPoint<I, F> lhs, Number rhs) {
  465. lhs *= FixedPoint<I, F>(rhs);
  466. return lhs;
  467. }
  468. template <size_t I, size_t F, class Number,
  469. class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
  470. CONSTEXPR14 FixedPoint<I, F> operator/(FixedPoint<I, F> lhs, Number rhs) {
  471. lhs /= FixedPoint<I, F>(rhs);
  472. return lhs;
  473. }
  474. template <size_t I, size_t F, class Number,
  475. class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
  476. CONSTEXPR14 FixedPoint<I, F> operator+(Number lhs, FixedPoint<I, F> rhs) {
  477. FixedPoint<I, F> tmp(lhs);
  478. tmp += rhs;
  479. return tmp;
  480. }
  481. template <size_t I, size_t F, class Number,
  482. class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
  483. CONSTEXPR14 FixedPoint<I, F> operator-(Number lhs, FixedPoint<I, F> rhs) {
  484. FixedPoint<I, F> tmp(lhs);
  485. tmp -= rhs;
  486. return tmp;
  487. }
  488. template <size_t I, size_t F, class Number,
  489. class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
  490. CONSTEXPR14 FixedPoint<I, F> operator*(Number lhs, FixedPoint<I, F> rhs) {
  491. FixedPoint<I, F> tmp(lhs);
  492. tmp *= rhs;
  493. return tmp;
  494. }
  495. template <size_t I, size_t F, class Number,
  496. class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
  497. CONSTEXPR14 FixedPoint<I, F> operator/(Number lhs, FixedPoint<I, F> rhs) {
  498. FixedPoint<I, F> tmp(lhs);
  499. tmp /= rhs;
  500. return tmp;
  501. }
  502. // shift operators
  503. template <size_t I, size_t F, class Integer,
  504. class = typename std::enable_if<std::is_integral<Integer>::value>::type>
  505. CONSTEXPR14 FixedPoint<I, F> operator<<(FixedPoint<I, F> lhs, Integer rhs) {
  506. lhs <<= rhs;
  507. return lhs;
  508. }
  509. template <size_t I, size_t F, class Integer,
  510. class = typename std::enable_if<std::is_integral<Integer>::value>::type>
  511. CONSTEXPR14 FixedPoint<I, F> operator>>(FixedPoint<I, F> lhs, Integer rhs) {
  512. lhs >>= rhs;
  513. return lhs;
  514. }
  515. // comparison operators
  516. template <size_t I, size_t F, class Number,
  517. class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
  518. constexpr bool operator>(FixedPoint<I, F> lhs, Number rhs) {
  519. return lhs > FixedPoint<I, F>(rhs);
  520. }
  521. template <size_t I, size_t F, class Number,
  522. class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
  523. constexpr bool operator<(FixedPoint<I, F> lhs, Number rhs) {
  524. return lhs < FixedPoint<I, F>(rhs);
  525. }
  526. template <size_t I, size_t F, class Number,
  527. class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
  528. constexpr bool operator>=(FixedPoint<I, F> lhs, Number rhs) {
  529. return lhs >= FixedPoint<I, F>(rhs);
  530. }
  531. template <size_t I, size_t F, class Number,
  532. class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
  533. constexpr bool operator<=(FixedPoint<I, F> lhs, Number rhs) {
  534. return lhs <= FixedPoint<I, F>(rhs);
  535. }
  536. template <size_t I, size_t F, class Number,
  537. class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
  538. constexpr bool operator==(FixedPoint<I, F> lhs, Number rhs) {
  539. return lhs == FixedPoint<I, F>(rhs);
  540. }
  541. template <size_t I, size_t F, class Number,
  542. class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
  543. constexpr bool operator!=(FixedPoint<I, F> lhs, Number rhs) {
  544. return lhs != FixedPoint<I, F>(rhs);
  545. }
  546. template <size_t I, size_t F, class Number,
  547. class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
  548. constexpr bool operator>(Number lhs, FixedPoint<I, F> rhs) {
  549. return FixedPoint<I, F>(lhs) > rhs;
  550. }
  551. template <size_t I, size_t F, class Number,
  552. class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
  553. constexpr bool operator<(Number lhs, FixedPoint<I, F> rhs) {
  554. return FixedPoint<I, F>(lhs) < rhs;
  555. }
  556. template <size_t I, size_t F, class Number,
  557. class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
  558. constexpr bool operator>=(Number lhs, FixedPoint<I, F> rhs) {
  559. return FixedPoint<I, F>(lhs) >= rhs;
  560. }
  561. template <size_t I, size_t F, class Number,
  562. class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
  563. constexpr bool operator<=(Number lhs, FixedPoint<I, F> rhs) {
  564. return FixedPoint<I, F>(lhs) <= rhs;
  565. }
  566. template <size_t I, size_t F, class Number,
  567. class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
  568. constexpr bool operator==(Number lhs, FixedPoint<I, F> rhs) {
  569. return FixedPoint<I, F>(lhs) == rhs;
  570. }
  571. template <size_t I, size_t F, class Number,
  572. class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
  573. constexpr bool operator!=(Number lhs, FixedPoint<I, F> rhs) {
  574. return FixedPoint<I, F>(lhs) != rhs;
  575. }
  576. } // namespace Common
  577. #undef CONSTEXPR14