summaryrefslogtreecommitdiff
path: root/src/common/fixed_point.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/fixed_point.h')
-rw-r--r--src/common/fixed_point.h726
1 files changed, 726 insertions, 0 deletions
diff --git a/src/common/fixed_point.h b/src/common/fixed_point.h
new file mode 100644
index 000000000..1d45e51b3
--- /dev/null
+++ b/src/common/fixed_point.h
@@ -0,0 +1,726 @@
1// From: https://github.com/eteran/cpp-utilities/blob/master/fixed/include/cpp-utilities/fixed.h
2// See also: http://stackoverflow.com/questions/79677/whats-the-best-way-to-do-fixed-point-math
3/*
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2015 Evan Teran
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in all
16 * copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 */
26
27#ifndef FIXED_H_
28#define FIXED_H_
29
30#if __cplusplus >= 201402L
31#define CONSTEXPR14 constexpr
32#else
33#define CONSTEXPR14
34#endif
35
36#include <cstddef> // for size_t
37#include <cstdint>
38#include <exception>
39#include <ostream>
40#include <type_traits>
41
42namespace Common {
43
44template <size_t I, size_t F>
45class FixedPoint;
46
47namespace detail {
48
49// helper templates to make magic with types :)
50// these allow us to determine resonable types from
51// a desired size, they also let us infer the next largest type
52// from a type which is nice for the division op
53template <size_t T>
54struct type_from_size {
55 using value_type = void;
56 using unsigned_type = void;
57 using signed_type = void;
58 static constexpr bool is_specialized = false;
59};
60
61#if defined(__GNUC__) && defined(__x86_64__) && !defined(__STRICT_ANSI__)
62template <>
63struct type_from_size<128> {
64 static constexpr bool is_specialized = true;
65 static constexpr size_t size = 128;
66
67 using value_type = __int128;
68 using unsigned_type = unsigned __int128;
69 using signed_type = __int128;
70 using next_size = type_from_size<256>;
71};
72#endif
73
74template <>
75struct type_from_size<64> {
76 static constexpr bool is_specialized = true;
77 static constexpr size_t size = 64;
78
79 using value_type = int64_t;
80 using unsigned_type = std::make_unsigned<value_type>::type;
81 using signed_type = std::make_signed<value_type>::type;
82 using next_size = type_from_size<128>;
83};
84
85template <>
86struct type_from_size<32> {
87 static constexpr bool is_specialized = true;
88 static constexpr size_t size = 32;
89
90 using value_type = int32_t;
91 using unsigned_type = std::make_unsigned<value_type>::type;
92 using signed_type = std::make_signed<value_type>::type;
93 using next_size = type_from_size<64>;
94};
95
96template <>
97struct type_from_size<16> {
98 static constexpr bool is_specialized = true;
99 static constexpr size_t size = 16;
100
101 using value_type = int16_t;
102 using unsigned_type = std::make_unsigned<value_type>::type;
103 using signed_type = std::make_signed<value_type>::type;
104 using next_size = type_from_size<32>;
105};
106
107template <>
108struct type_from_size<8> {
109 static constexpr bool is_specialized = true;
110 static constexpr size_t size = 8;
111
112 using value_type = int8_t;
113 using unsigned_type = std::make_unsigned<value_type>::type;
114 using signed_type = std::make_signed<value_type>::type;
115 using next_size = type_from_size<16>;
116};
117
118// this is to assist in adding support for non-native base
119// types (for adding big-int support), this should be fine
120// unless your bit-int class doesn't nicely support casting
121template <class B, class N>
122constexpr B next_to_base(N rhs) {
123 return static_cast<B>(rhs);
124}
125
126struct divide_by_zero : std::exception {};
127
128template <size_t I, size_t F>
129CONSTEXPR14 FixedPoint<I, F> divide(
130 FixedPoint<I, F> numerator, FixedPoint<I, F> denominator, FixedPoint<I, F>& remainder,
131 typename std::enable_if<type_from_size<I + F>::next_size::is_specialized>::type* = nullptr) {
132
133 using next_type = typename FixedPoint<I, F>::next_type;
134 using base_type = typename FixedPoint<I, F>::base_type;
135 constexpr size_t fractional_bits = FixedPoint<I, F>::fractional_bits;
136
137 next_type t(numerator.to_raw());
138 t <<= fractional_bits;
139
140 FixedPoint<I, F> quotient;
141
142 quotient = FixedPoint<I, F>::from_base(next_to_base<base_type>(t / denominator.to_raw()));
143 remainder = FixedPoint<I, F>::from_base(next_to_base<base_type>(t % denominator.to_raw()));
144
145 return quotient;
146}
147
148template <size_t I, size_t F>
149CONSTEXPR14 FixedPoint<I, F> divide(
150 FixedPoint<I, F> numerator, FixedPoint<I, F> denominator, FixedPoint<I, F>& remainder,
151 typename std::enable_if<!type_from_size<I + F>::next_size::is_specialized>::type* = nullptr) {
152
153 using unsigned_type = typename FixedPoint<I, F>::unsigned_type;
154
155 constexpr int bits = FixedPoint<I, F>::total_bits;
156
157 if (denominator == 0) {
158 throw divide_by_zero();
159 } else {
160
161 int sign = 0;
162
163 FixedPoint<I, F> quotient;
164
165 if (numerator < 0) {
166 sign ^= 1;
167 numerator = -numerator;
168 }
169
170 if (denominator < 0) {
171 sign ^= 1;
172 denominator = -denominator;
173 }
174
175 unsigned_type n = numerator.to_raw();
176 unsigned_type d = denominator.to_raw();
177 unsigned_type x = 1;
178 unsigned_type answer = 0;
179
180 // egyptian division algorithm
181 while ((n >= d) && (((d >> (bits - 1)) & 1) == 0)) {
182 x <<= 1;
183 d <<= 1;
184 }
185
186 while (x != 0) {
187 if (n >= d) {
188 n -= d;
189 answer += x;
190 }
191
192 x >>= 1;
193 d >>= 1;
194 }
195
196 unsigned_type l1 = n;
197 unsigned_type l2 = denominator.to_raw();
198
199 // calculate the lower bits (needs to be unsigned)
200 while (l1 >> (bits - F) > 0) {
201 l1 >>= 1;
202 l2 >>= 1;
203 }
204 const unsigned_type lo = (l1 << F) / l2;
205
206 quotient = FixedPoint<I, F>::from_base((answer << F) | lo);
207 remainder = n;
208
209 if (sign) {
210 quotient = -quotient;
211 }
212
213 return quotient;
214 }
215}
216
217// this is the usual implementation of multiplication
218template <size_t I, size_t F>
219CONSTEXPR14 FixedPoint<I, F> multiply(
220 FixedPoint<I, F> lhs, FixedPoint<I, F> rhs,
221 typename std::enable_if<type_from_size<I + F>::next_size::is_specialized>::type* = nullptr) {
222
223 using next_type = typename FixedPoint<I, F>::next_type;
224 using base_type = typename FixedPoint<I, F>::base_type;
225
226 constexpr size_t fractional_bits = FixedPoint<I, F>::fractional_bits;
227
228 next_type t(static_cast<next_type>(lhs.to_raw()) * static_cast<next_type>(rhs.to_raw()));
229 t >>= fractional_bits;
230
231 return FixedPoint<I, F>::from_base(next_to_base<base_type>(t));
232}
233
234// this is the fall back version we use when we don't have a next size
235// it is slightly slower, but is more robust since it doesn't
236// require and upgraded type
237template <size_t I, size_t F>
238CONSTEXPR14 FixedPoint<I, F> multiply(
239 FixedPoint<I, F> lhs, FixedPoint<I, F> rhs,
240 typename std::enable_if<!type_from_size<I + F>::next_size::is_specialized>::type* = nullptr) {
241
242 using base_type = typename FixedPoint<I, F>::base_type;
243
244 constexpr size_t fractional_bits = FixedPoint<I, F>::fractional_bits;
245 constexpr base_type integer_mask = FixedPoint<I, F>::integer_mask;
246 constexpr base_type fractional_mask = FixedPoint<I, F>::fractional_mask;
247
248 // more costly but doesn't need a larger type
249 const base_type a_hi = (lhs.to_raw() & integer_mask) >> fractional_bits;
250 const base_type b_hi = (rhs.to_raw() & integer_mask) >> fractional_bits;
251 const base_type a_lo = (lhs.to_raw() & fractional_mask);
252 const base_type b_lo = (rhs.to_raw() & fractional_mask);
253
254 const base_type x1 = a_hi * b_hi;
255 const base_type x2 = a_hi * b_lo;
256 const base_type x3 = a_lo * b_hi;
257 const base_type x4 = a_lo * b_lo;
258
259 return FixedPoint<I, F>::from_base((x1 << fractional_bits) + (x3 + x2) +
260 (x4 >> fractional_bits));
261}
262} // namespace detail
263
264template <size_t I, size_t F>
265class FixedPoint {
266 static_assert(detail::type_from_size<I + F>::is_specialized, "invalid combination of sizes");
267
268public:
269 static constexpr size_t fractional_bits = F;
270 static constexpr size_t integer_bits = I;
271 static constexpr size_t total_bits = I + F;
272
273 using base_type_info = detail::type_from_size<total_bits>;
274
275 using base_type = typename base_type_info::value_type;
276 using next_type = typename base_type_info::next_size::value_type;
277 using unsigned_type = typename base_type_info::unsigned_type;
278
279public:
280#ifdef __GNUC__
281#pragma GCC diagnostic push
282#pragma GCC diagnostic ignored "-Woverflow"
283#endif
284 static constexpr base_type fractional_mask =
285 ~(static_cast<unsigned_type>(~base_type(0)) << fractional_bits);
286 static constexpr base_type integer_mask = ~fractional_mask;
287#ifdef __GNUC__
288#pragma GCC diagnostic pop
289#endif
290
291public:
292 static constexpr base_type one = base_type(1) << fractional_bits;
293
294public: // constructors
295 FixedPoint() = default;
296 FixedPoint(const FixedPoint&) = default;
297 FixedPoint(FixedPoint&&) = default;
298 FixedPoint& operator=(const FixedPoint&) = default;
299
300 template <class Number>
301 constexpr FixedPoint(
302 Number n, typename std::enable_if<std::is_arithmetic<Number>::value>::type* = nullptr)
303 : data_(static_cast<base_type>(n * one)) {}
304
305public: // conversion
306 template <size_t I2, size_t F2>
307 CONSTEXPR14 explicit FixedPoint(FixedPoint<I2, F2> other) {
308 static_assert(I2 <= I && F2 <= F, "Scaling conversion can only upgrade types");
309 using T = FixedPoint<I2, F2>;
310
311 const base_type fractional = (other.data_ & T::fractional_mask);
312 const base_type integer = (other.data_ & T::integer_mask) >> T::fractional_bits;
313 data_ =
314 (integer << fractional_bits) | (fractional << (fractional_bits - T::fractional_bits));
315 }
316
317private:
318 // this makes it simpler to create a FixedPoint point object from
319 // a native type without scaling
320 // use "FixedPoint::from_base" in order to perform this.
321 struct NoScale {};
322
323 constexpr FixedPoint(base_type n, const NoScale&) : data_(n) {}
324
325public:
326 static constexpr FixedPoint from_base(base_type n) {
327 return FixedPoint(n, NoScale());
328 }
329
330public: // comparison operators
331 constexpr bool operator==(FixedPoint rhs) const {
332 return data_ == rhs.data_;
333 }
334
335 constexpr bool operator!=(FixedPoint rhs) const {
336 return data_ != rhs.data_;
337 }
338
339 constexpr bool operator<(FixedPoint rhs) const {
340 return data_ < rhs.data_;
341 }
342
343 constexpr bool operator>(FixedPoint rhs) const {
344 return data_ > rhs.data_;
345 }
346
347 constexpr bool operator<=(FixedPoint rhs) const {
348 return data_ <= rhs.data_;
349 }
350
351 constexpr bool operator>=(FixedPoint rhs) const {
352 return data_ >= rhs.data_;
353 }
354
355public: // unary operators
356 constexpr bool operator!() const {
357 return !data_;
358 }
359
360 constexpr FixedPoint operator~() const {
361 // NOTE(eteran): this will often appear to "just negate" the value
362 // that is not an error, it is because -x == (~x+1)
363 // and that "+1" is adding an infinitesimally small fraction to the
364 // complimented value
365 return FixedPoint::from_base(~data_);
366 }
367
368 constexpr FixedPoint operator-() const {
369 return FixedPoint::from_base(-data_);
370 }
371
372 constexpr FixedPoint operator+() const {
373 return FixedPoint::from_base(+data_);
374 }
375
376 CONSTEXPR14 FixedPoint& operator++() {
377 data_ += one;
378 return *this;
379 }
380
381 CONSTEXPR14 FixedPoint& operator--() {
382 data_ -= one;
383 return *this;
384 }
385
386 CONSTEXPR14 FixedPoint operator++(int) {
387 FixedPoint tmp(*this);
388 data_ += one;
389 return tmp;
390 }
391
392 CONSTEXPR14 FixedPoint operator--(int) {
393 FixedPoint tmp(*this);
394 data_ -= one;
395 return tmp;
396 }
397
398public: // basic math operators
399 CONSTEXPR14 FixedPoint& operator+=(FixedPoint n) {
400 data_ += n.data_;
401 return *this;
402 }
403
404 CONSTEXPR14 FixedPoint& operator-=(FixedPoint n) {
405 data_ -= n.data_;
406 return *this;
407 }
408
409 CONSTEXPR14 FixedPoint& operator*=(FixedPoint n) {
410 return assign(detail::multiply(*this, n));
411 }
412
413 CONSTEXPR14 FixedPoint& operator/=(FixedPoint n) {
414 FixedPoint temp;
415 return assign(detail::divide(*this, n, temp));
416 }
417
418private:
419 CONSTEXPR14 FixedPoint& assign(FixedPoint rhs) {
420 data_ = rhs.data_;
421 return *this;
422 }
423
424public: // binary math operators, effects underlying bit pattern since these
425 // don't really typically make sense for non-integer values
426 CONSTEXPR14 FixedPoint& operator&=(FixedPoint n) {
427 data_ &= n.data_;
428 return *this;
429 }
430
431 CONSTEXPR14 FixedPoint& operator|=(FixedPoint n) {
432 data_ |= n.data_;
433 return *this;
434 }
435
436 CONSTEXPR14 FixedPoint& operator^=(FixedPoint n) {
437 data_ ^= n.data_;
438 return *this;
439 }
440
441 template <class Integer,
442 class = typename std::enable_if<std::is_integral<Integer>::value>::type>
443 CONSTEXPR14 FixedPoint& operator>>=(Integer n) {
444 data_ >>= n;
445 return *this;
446 }
447
448 template <class Integer,
449 class = typename std::enable_if<std::is_integral<Integer>::value>::type>
450 CONSTEXPR14 FixedPoint& operator<<=(Integer n) {
451 data_ <<= n;
452 return *this;
453 }
454
455public: // conversion to basic types
456 constexpr void round_up() {
457 data_ += (data_ & fractional_mask) >> 1;
458 }
459
460 constexpr int to_int() {
461 round_up();
462 return static_cast<int>((data_ & integer_mask) >> fractional_bits);
463 }
464
465 constexpr unsigned int to_uint() const {
466 round_up();
467 return static_cast<unsigned int>((data_ & integer_mask) >> fractional_bits);
468 }
469
470 constexpr int64_t to_long() {
471 round_up();
472 return static_cast<int64_t>((data_ & integer_mask) >> fractional_bits);
473 }
474
475 constexpr int to_int_floor() const {
476 return static_cast<int>((data_ & integer_mask) >> fractional_bits);
477 }
478
479 constexpr int64_t to_long_floor() {
480 return static_cast<int64_t>((data_ & integer_mask) >> fractional_bits);
481 }
482
483 constexpr unsigned int to_uint_floor() const {
484 return static_cast<unsigned int>((data_ & integer_mask) >> fractional_bits);
485 }
486
487 constexpr float to_float() const {
488 return static_cast<float>(data_) / FixedPoint::one;
489 }
490
491 constexpr double to_double() const {
492 return static_cast<double>(data_) / FixedPoint::one;
493 }
494
495 constexpr base_type to_raw() const {
496 return data_;
497 }
498
499 constexpr void clear_int() {
500 data_ &= fractional_mask;
501 }
502
503 constexpr base_type get_frac() const {
504 return data_ & fractional_mask;
505 }
506
507public:
508 CONSTEXPR14 void swap(FixedPoint& rhs) {
509 using std::swap;
510 swap(data_, rhs.data_);
511 }
512
513public:
514 base_type data_;
515};
516
517// if we have the same fractional portion, but differing integer portions, we trivially upgrade the
518// smaller type
519template <size_t I1, size_t I2, size_t F>
520CONSTEXPR14 typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type
521operator+(FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) {
522
523 using T = typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type;
524
525 const T l = T::from_base(lhs.to_raw());
526 const T r = T::from_base(rhs.to_raw());
527 return l + r;
528}
529
530template <size_t I1, size_t I2, size_t F>
531CONSTEXPR14 typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type
532operator-(FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) {
533
534 using T = typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type;
535
536 const T l = T::from_base(lhs.to_raw());
537 const T r = T::from_base(rhs.to_raw());
538 return l - r;
539}
540
541template <size_t I1, size_t I2, size_t F>
542CONSTEXPR14 typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type
543operator*(FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) {
544
545 using T = typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type;
546
547 const T l = T::from_base(lhs.to_raw());
548 const T r = T::from_base(rhs.to_raw());
549 return l * r;
550}
551
552template <size_t I1, size_t I2, size_t F>
553CONSTEXPR14 typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type
554operator/(FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) {
555
556 using T = typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type;
557
558 const T l = T::from_base(lhs.to_raw());
559 const T r = T::from_base(rhs.to_raw());
560 return l / r;
561}
562
563template <size_t I, size_t F>
564std::ostream& operator<<(std::ostream& os, FixedPoint<I, F> f) {
565 os << f.to_double();
566 return os;
567}
568
569// basic math operators
570template <size_t I, size_t F>
571CONSTEXPR14 FixedPoint<I, F> operator+(FixedPoint<I, F> lhs, FixedPoint<I, F> rhs) {
572 lhs += rhs;
573 return lhs;
574}
575template <size_t I, size_t F>
576CONSTEXPR14 FixedPoint<I, F> operator-(FixedPoint<I, F> lhs, FixedPoint<I, F> rhs) {
577 lhs -= rhs;
578 return lhs;
579}
580template <size_t I, size_t F>
581CONSTEXPR14 FixedPoint<I, F> operator*(FixedPoint<I, F> lhs, FixedPoint<I, F> rhs) {
582 lhs *= rhs;
583 return lhs;
584}
585template <size_t I, size_t F>
586CONSTEXPR14 FixedPoint<I, F> operator/(FixedPoint<I, F> lhs, FixedPoint<I, F> rhs) {
587 lhs /= rhs;
588 return lhs;
589}
590
591template <size_t I, size_t F, class Number,
592 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
593CONSTEXPR14 FixedPoint<I, F> operator+(FixedPoint<I, F> lhs, Number rhs) {
594 lhs += FixedPoint<I, F>(rhs);
595 return lhs;
596}
597template <size_t I, size_t F, class Number,
598 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
599CONSTEXPR14 FixedPoint<I, F> operator-(FixedPoint<I, F> lhs, Number rhs) {
600 lhs -= FixedPoint<I, F>(rhs);
601 return lhs;
602}
603template <size_t I, size_t F, class Number,
604 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
605CONSTEXPR14 FixedPoint<I, F> operator*(FixedPoint<I, F> lhs, Number rhs) {
606 lhs *= FixedPoint<I, F>(rhs);
607 return lhs;
608}
609template <size_t I, size_t F, class Number,
610 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
611CONSTEXPR14 FixedPoint<I, F> operator/(FixedPoint<I, F> lhs, Number rhs) {
612 lhs /= FixedPoint<I, F>(rhs);
613 return lhs;
614}
615
616template <size_t I, size_t F, class Number,
617 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
618CONSTEXPR14 FixedPoint<I, F> operator+(Number lhs, FixedPoint<I, F> rhs) {
619 FixedPoint<I, F> tmp(lhs);
620 tmp += rhs;
621 return tmp;
622}
623template <size_t I, size_t F, class Number,
624 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
625CONSTEXPR14 FixedPoint<I, F> operator-(Number lhs, FixedPoint<I, F> rhs) {
626 FixedPoint<I, F> tmp(lhs);
627 tmp -= rhs;
628 return tmp;
629}
630template <size_t I, size_t F, class Number,
631 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
632CONSTEXPR14 FixedPoint<I, F> operator*(Number lhs, FixedPoint<I, F> rhs) {
633 FixedPoint<I, F> tmp(lhs);
634 tmp *= rhs;
635 return tmp;
636}
637template <size_t I, size_t F, class Number,
638 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
639CONSTEXPR14 FixedPoint<I, F> operator/(Number lhs, FixedPoint<I, F> rhs) {
640 FixedPoint<I, F> tmp(lhs);
641 tmp /= rhs;
642 return tmp;
643}
644
645// shift operators
646template <size_t I, size_t F, class Integer,
647 class = typename std::enable_if<std::is_integral<Integer>::value>::type>
648CONSTEXPR14 FixedPoint<I, F> operator<<(FixedPoint<I, F> lhs, Integer rhs) {
649 lhs <<= rhs;
650 return lhs;
651}
652template <size_t I, size_t F, class Integer,
653 class = typename std::enable_if<std::is_integral<Integer>::value>::type>
654CONSTEXPR14 FixedPoint<I, F> operator>>(FixedPoint<I, F> lhs, Integer rhs) {
655 lhs >>= rhs;
656 return lhs;
657}
658
659// comparison operators
660template <size_t I, size_t F, class Number,
661 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
662constexpr bool operator>(FixedPoint<I, F> lhs, Number rhs) {
663 return lhs > FixedPoint<I, F>(rhs);
664}
665template <size_t I, size_t F, class Number,
666 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
667constexpr bool operator<(FixedPoint<I, F> lhs, Number rhs) {
668 return lhs < FixedPoint<I, F>(rhs);
669}
670template <size_t I, size_t F, class Number,
671 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
672constexpr bool operator>=(FixedPoint<I, F> lhs, Number rhs) {
673 return lhs >= FixedPoint<I, F>(rhs);
674}
675template <size_t I, size_t F, class Number,
676 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
677constexpr bool operator<=(FixedPoint<I, F> lhs, Number rhs) {
678 return lhs <= FixedPoint<I, F>(rhs);
679}
680template <size_t I, size_t F, class Number,
681 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
682constexpr bool operator==(FixedPoint<I, F> lhs, Number rhs) {
683 return lhs == FixedPoint<I, F>(rhs);
684}
685template <size_t I, size_t F, class Number,
686 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
687constexpr bool operator!=(FixedPoint<I, F> lhs, Number rhs) {
688 return lhs != FixedPoint<I, F>(rhs);
689}
690
691template <size_t I, size_t F, class Number,
692 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
693constexpr bool operator>(Number lhs, FixedPoint<I, F> rhs) {
694 return FixedPoint<I, F>(lhs) > rhs;
695}
696template <size_t I, size_t F, class Number,
697 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
698constexpr bool operator<(Number lhs, FixedPoint<I, F> rhs) {
699 return FixedPoint<I, F>(lhs) < rhs;
700}
701template <size_t I, size_t F, class Number,
702 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
703constexpr bool operator>=(Number lhs, FixedPoint<I, F> rhs) {
704 return FixedPoint<I, F>(lhs) >= rhs;
705}
706template <size_t I, size_t F, class Number,
707 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
708constexpr bool operator<=(Number lhs, FixedPoint<I, F> rhs) {
709 return FixedPoint<I, F>(lhs) <= rhs;
710}
711template <size_t I, size_t F, class Number,
712 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
713constexpr bool operator==(Number lhs, FixedPoint<I, F> rhs) {
714 return FixedPoint<I, F>(lhs) == rhs;
715}
716template <size_t I, size_t F, class Number,
717 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
718constexpr bool operator!=(Number lhs, FixedPoint<I, F> rhs) {
719 return FixedPoint<I, F>(lhs) != rhs;
720}
721
722} // namespace Common
723
724#undef CONSTEXPR14
725
726#endif