summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/concepts.h8
-rw-r--r--src/common/fixed_point.h120
2 files changed, 56 insertions, 72 deletions
diff --git a/src/common/concepts.h b/src/common/concepts.h
index a97555f6a..e8ce30dfe 100644
--- a/src/common/concepts.h
+++ b/src/common/concepts.h
@@ -34,4 +34,12 @@ concept DerivedFrom = requires {
34template <typename From, typename To> 34template <typename From, typename To>
35concept ConvertibleTo = std::is_convertible_v<From, To>; 35concept ConvertibleTo = std::is_convertible_v<From, To>;
36 36
37// No equivalents in the stdlib
38
39template <typename T>
40concept IsArithmetic = std::is_arithmetic_v<T>;
41
42template <typename T>
43concept IsIntegral = std::is_integral_v<T>;
44
37} // namespace Common 45} // namespace Common
diff --git a/src/common/fixed_point.h b/src/common/fixed_point.h
index 6eb6afe2f..b2e489841 100644
--- a/src/common/fixed_point.h
+++ b/src/common/fixed_point.h
@@ -12,6 +12,8 @@
12#include <ostream> 12#include <ostream>
13#include <type_traits> 13#include <type_traits>
14 14
15#include <common/concepts.h>
16
15namespace Common { 17namespace Common {
16 18
17template <size_t I, size_t F> 19template <size_t I, size_t F>
@@ -50,8 +52,8 @@ struct type_from_size<64> {
50 static constexpr size_t size = 64; 52 static constexpr size_t size = 64;
51 53
52 using value_type = int64_t; 54 using value_type = int64_t;
53 using unsigned_type = std::make_unsigned<value_type>::type; 55 using unsigned_type = std::make_unsigned_t<value_type>;
54 using signed_type = std::make_signed<value_type>::type; 56 using signed_type = std::make_signed_t<value_type>;
55 using next_size = type_from_size<128>; 57 using next_size = type_from_size<128>;
56}; 58};
57 59
@@ -61,8 +63,8 @@ struct type_from_size<32> {
61 static constexpr size_t size = 32; 63 static constexpr size_t size = 32;
62 64
63 using value_type = int32_t; 65 using value_type = int32_t;
64 using unsigned_type = std::make_unsigned<value_type>::type; 66 using unsigned_type = std::make_unsigned_t<value_type>;
65 using signed_type = std::make_signed<value_type>::type; 67 using signed_type = std::make_signed_t<value_type>;
66 using next_size = type_from_size<64>; 68 using next_size = type_from_size<64>;
67}; 69};
68 70
@@ -72,8 +74,8 @@ struct type_from_size<16> {
72 static constexpr size_t size = 16; 74 static constexpr size_t size = 16;
73 75
74 using value_type = int16_t; 76 using value_type = int16_t;
75 using unsigned_type = std::make_unsigned<value_type>::type; 77 using unsigned_type = std::make_unsigned_t<value_type>;
76 using signed_type = std::make_signed<value_type>::type; 78 using signed_type = std::make_signed_t<value_type>;
77 using next_size = type_from_size<32>; 79 using next_size = type_from_size<32>;
78}; 80};
79 81
@@ -83,8 +85,8 @@ struct type_from_size<8> {
83 static constexpr size_t size = 8; 85 static constexpr size_t size = 8;
84 86
85 using value_type = int8_t; 87 using value_type = int8_t;
86 using unsigned_type = std::make_unsigned<value_type>::type; 88 using unsigned_type = std::make_unsigned_t<value_type>;
87 using signed_type = std::make_signed<value_type>::type; 89 using signed_type = std::make_signed_t<value_type>;
88 using next_size = type_from_size<16>; 90 using next_size = type_from_size<16>;
89}; 91};
90 92
@@ -101,7 +103,7 @@ struct divide_by_zero : std::exception {};
101template <size_t I, size_t F> 103template <size_t I, size_t F>
102constexpr FixedPoint<I, F> divide( 104constexpr FixedPoint<I, F> divide(
103 FixedPoint<I, F> numerator, FixedPoint<I, F> denominator, FixedPoint<I, F>& remainder, 105 FixedPoint<I, F> numerator, FixedPoint<I, F> denominator, FixedPoint<I, F>& remainder,
104 typename std::enable_if<type_from_size<I + F>::next_size::is_specialized>::type* = nullptr) { 106 std::enable_if_t<type_from_size<I + F>::next_size::is_specialized>* = nullptr) {
105 107
106 using next_type = typename FixedPoint<I, F>::next_type; 108 using next_type = typename FixedPoint<I, F>::next_type;
107 using base_type = typename FixedPoint<I, F>::base_type; 109 using base_type = typename FixedPoint<I, F>::base_type;
@@ -121,7 +123,7 @@ constexpr FixedPoint<I, F> divide(
121template <size_t I, size_t F> 123template <size_t I, size_t F>
122constexpr FixedPoint<I, F> divide( 124constexpr FixedPoint<I, F> divide(
123 FixedPoint<I, F> numerator, FixedPoint<I, F> denominator, FixedPoint<I, F>& remainder, 125 FixedPoint<I, F> numerator, FixedPoint<I, F> denominator, FixedPoint<I, F>& remainder,
124 typename std::enable_if<!type_from_size<I + F>::next_size::is_specialized>::type* = nullptr) { 126 std::enable_if_t<!type_from_size<I + F>::next_size::is_specialized>* = nullptr) {
125 127
126 using unsigned_type = typename FixedPoint<I, F>::unsigned_type; 128 using unsigned_type = typename FixedPoint<I, F>::unsigned_type;
127 129
@@ -191,7 +193,7 @@ constexpr FixedPoint<I, F> divide(
191template <size_t I, size_t F> 193template <size_t I, size_t F>
192constexpr FixedPoint<I, F> multiply( 194constexpr FixedPoint<I, F> multiply(
193 FixedPoint<I, F> lhs, FixedPoint<I, F> rhs, 195 FixedPoint<I, F> lhs, FixedPoint<I, F> rhs,
194 typename std::enable_if<type_from_size<I + F>::next_size::is_specialized>::type* = nullptr) { 196 std::enable_if_t<type_from_size<I + F>::next_size::is_specialized>* = nullptr) {
195 197
196 using next_type = typename FixedPoint<I, F>::next_type; 198 using next_type = typename FixedPoint<I, F>::next_type;
197 using base_type = typename FixedPoint<I, F>::base_type; 199 using base_type = typename FixedPoint<I, F>::base_type;
@@ -210,7 +212,7 @@ constexpr FixedPoint<I, F> multiply(
210template <size_t I, size_t F> 212template <size_t I, size_t F>
211constexpr FixedPoint<I, F> multiply( 213constexpr FixedPoint<I, F> multiply(
212 FixedPoint<I, F> lhs, FixedPoint<I, F> rhs, 214 FixedPoint<I, F> lhs, FixedPoint<I, F> rhs,
213 typename std::enable_if<!type_from_size<I + F>::next_size::is_specialized>::type* = nullptr) { 215 std::enable_if_t<!type_from_size<I + F>::next_size::is_specialized>* = nullptr) {
214 216
215 using base_type = typename FixedPoint<I, F>::base_type; 217 using base_type = typename FixedPoint<I, F>::base_type;
216 218
@@ -270,10 +272,8 @@ public: // constructors
270 FixedPoint(FixedPoint&&) = default; 272 FixedPoint(FixedPoint&&) = default;
271 FixedPoint& operator=(const FixedPoint&) = default; 273 FixedPoint& operator=(const FixedPoint&) = default;
272 274
273 template <class Number> 275 template <IsArithmetic Number>
274 constexpr FixedPoint( 276 constexpr FixedPoint(Number n) : data_(static_cast<base_type>(n * one)) {}
275 Number n, typename std::enable_if<std::is_arithmetic<Number>::value>::type* = nullptr)
276 : data_(static_cast<base_type>(n * one)) {}
277 277
278public: // conversion 278public: // conversion
279 template <size_t I2, size_t F2> 279 template <size_t I2, size_t F2>
@@ -411,15 +411,13 @@ public: // binary math operators, effects underlying bit pattern since these
411 return *this; 411 return *this;
412 } 412 }
413 413
414 template <class Integer, 414 template <IsIntegral Integer>
415 class = typename std::enable_if<std::is_integral<Integer>::value>::type>
416 constexpr FixedPoint& operator>>=(Integer n) { 415 constexpr FixedPoint& operator>>=(Integer n) {
417 data_ >>= n; 416 data_ >>= n;
418 return *this; 417 return *this;
419 } 418 }
420 419
421 template <class Integer, 420 template <IsIntegral Integer>
422 class = typename std::enable_if<std::is_integral<Integer>::value>::type>
423 constexpr FixedPoint& operator<<=(Integer n) { 421 constexpr FixedPoint& operator<<=(Integer n) {
424 data_ <<= n; 422 data_ <<= n;
425 return *this; 423 return *this;
@@ -490,10 +488,10 @@ public:
490// if we have the same fractional portion, but differing integer portions, we trivially upgrade the 488// if we have the same fractional portion, but differing integer portions, we trivially upgrade the
491// smaller type 489// smaller type
492template <size_t I1, size_t I2, size_t F> 490template <size_t I1, size_t I2, size_t F>
493constexpr typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type operator+( 491constexpr std::conditional_t<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>> operator+(
494 FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) { 492 FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) {
495 493
496 using T = typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type; 494 using T = std::conditional_t<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>;
497 495
498 const T l = T::from_base(lhs.to_raw()); 496 const T l = T::from_base(lhs.to_raw());
499 const T r = T::from_base(rhs.to_raw()); 497 const T r = T::from_base(rhs.to_raw());
@@ -501,10 +499,10 @@ constexpr typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2,
501} 499}
502 500
503template <size_t I1, size_t I2, size_t F> 501template <size_t I1, size_t I2, size_t F>
504constexpr typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type operator-( 502constexpr std::conditional_t<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>> operator-(
505 FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) { 503 FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) {
506 504
507 using T = typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type; 505 using T = std::conditional_t<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>;
508 506
509 const T l = T::from_base(lhs.to_raw()); 507 const T l = T::from_base(lhs.to_raw());
510 const T r = T::from_base(rhs.to_raw()); 508 const T r = T::from_base(rhs.to_raw());
@@ -512,10 +510,10 @@ constexpr typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2,
512} 510}
513 511
514template <size_t I1, size_t I2, size_t F> 512template <size_t I1, size_t I2, size_t F>
515constexpr typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type operator*( 513constexpr std::conditional_t<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>> operator*(
516 FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) { 514 FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) {
517 515
518 using T = typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type; 516 using T = std::conditional_t<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>;
519 517
520 const T l = T::from_base(lhs.to_raw()); 518 const T l = T::from_base(lhs.to_raw());
521 const T r = T::from_base(rhs.to_raw()); 519 const T r = T::from_base(rhs.to_raw());
@@ -523,10 +521,10 @@ constexpr typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2,
523} 521}
524 522
525template <size_t I1, size_t I2, size_t F> 523template <size_t I1, size_t I2, size_t F>
526constexpr typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type operator/( 524constexpr std::conditional_t<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>> operator/(
527 FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) { 525 FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) {
528 526
529 using T = typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type; 527 using T = std::conditional_t<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>;
530 528
531 const T l = T::from_base(lhs.to_raw()); 529 const T l = T::from_base(lhs.to_raw());
532 const T r = T::from_base(rhs.to_raw()); 530 const T r = T::from_base(rhs.to_raw());
@@ -561,54 +559,46 @@ constexpr FixedPoint<I, F> operator/(FixedPoint<I, F> lhs, FixedPoint<I, F> rhs)
561 return lhs; 559 return lhs;
562} 560}
563 561
564template <size_t I, size_t F, class Number, 562template <size_t I, size_t F, IsArithmetic Number>
565 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
566constexpr FixedPoint<I, F> operator+(FixedPoint<I, F> lhs, Number rhs) { 563constexpr FixedPoint<I, F> operator+(FixedPoint<I, F> lhs, Number rhs) {
567 lhs += FixedPoint<I, F>(rhs); 564 lhs += FixedPoint<I, F>(rhs);
568 return lhs; 565 return lhs;
569} 566}
570template <size_t I, size_t F, class Number, 567template <size_t I, size_t F, IsArithmetic Number>
571 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
572constexpr FixedPoint<I, F> operator-(FixedPoint<I, F> lhs, Number rhs) { 568constexpr FixedPoint<I, F> operator-(FixedPoint<I, F> lhs, Number rhs) {
573 lhs -= FixedPoint<I, F>(rhs); 569 lhs -= FixedPoint<I, F>(rhs);
574 return lhs; 570 return lhs;
575} 571}
576template <size_t I, size_t F, class Number, 572template <size_t I, size_t F, IsArithmetic Number>
577 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
578constexpr FixedPoint<I, F> operator*(FixedPoint<I, F> lhs, Number rhs) { 573constexpr FixedPoint<I, F> operator*(FixedPoint<I, F> lhs, Number rhs) {
579 lhs *= FixedPoint<I, F>(rhs); 574 lhs *= FixedPoint<I, F>(rhs);
580 return lhs; 575 return lhs;
581} 576}
582template <size_t I, size_t F, class Number, 577template <size_t I, size_t F, IsArithmetic Number>
583 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
584constexpr FixedPoint<I, F> operator/(FixedPoint<I, F> lhs, Number rhs) { 578constexpr FixedPoint<I, F> operator/(FixedPoint<I, F> lhs, Number rhs) {
585 lhs /= FixedPoint<I, F>(rhs); 579 lhs /= FixedPoint<I, F>(rhs);
586 return lhs; 580 return lhs;
587} 581}
588 582
589template <size_t I, size_t F, class Number, 583template <size_t I, size_t F, IsArithmetic Number>
590 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
591constexpr FixedPoint<I, F> operator+(Number lhs, FixedPoint<I, F> rhs) { 584constexpr FixedPoint<I, F> operator+(Number lhs, FixedPoint<I, F> rhs) {
592 FixedPoint<I, F> tmp(lhs); 585 FixedPoint<I, F> tmp(lhs);
593 tmp += rhs; 586 tmp += rhs;
594 return tmp; 587 return tmp;
595} 588}
596template <size_t I, size_t F, class Number, 589template <size_t I, size_t F, IsArithmetic Number>
597 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
598constexpr FixedPoint<I, F> operator-(Number lhs, FixedPoint<I, F> rhs) { 590constexpr FixedPoint<I, F> operator-(Number lhs, FixedPoint<I, F> rhs) {
599 FixedPoint<I, F> tmp(lhs); 591 FixedPoint<I, F> tmp(lhs);
600 tmp -= rhs; 592 tmp -= rhs;
601 return tmp; 593 return tmp;
602} 594}
603template <size_t I, size_t F, class Number, 595template <size_t I, size_t F, IsArithmetic Number>
604 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
605constexpr FixedPoint<I, F> operator*(Number lhs, FixedPoint<I, F> rhs) { 596constexpr FixedPoint<I, F> operator*(Number lhs, FixedPoint<I, F> rhs) {
606 FixedPoint<I, F> tmp(lhs); 597 FixedPoint<I, F> tmp(lhs);
607 tmp *= rhs; 598 tmp *= rhs;
608 return tmp; 599 return tmp;
609} 600}
610template <size_t I, size_t F, class Number, 601template <size_t I, size_t F, IsArithmetic Number>
611 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
612constexpr FixedPoint<I, F> operator/(Number lhs, FixedPoint<I, F> rhs) { 602constexpr FixedPoint<I, F> operator/(Number lhs, FixedPoint<I, F> rhs) {
613 FixedPoint<I, F> tmp(lhs); 603 FixedPoint<I, F> tmp(lhs);
614 tmp /= rhs; 604 tmp /= rhs;
@@ -616,78 +606,64 @@ constexpr FixedPoint<I, F> operator/(Number lhs, FixedPoint<I, F> rhs) {
616} 606}
617 607
618// shift operators 608// shift operators
619template <size_t I, size_t F, class Integer, 609template <size_t I, size_t F, IsIntegral Integer>
620 class = typename std::enable_if<std::is_integral<Integer>::value>::type>
621constexpr FixedPoint<I, F> operator<<(FixedPoint<I, F> lhs, Integer rhs) { 610constexpr FixedPoint<I, F> operator<<(FixedPoint<I, F> lhs, Integer rhs) {
622 lhs <<= rhs; 611 lhs <<= rhs;
623 return lhs; 612 return lhs;
624} 613}
625template <size_t I, size_t F, class Integer, 614template <size_t I, size_t F, IsIntegral Integer>
626 class = typename std::enable_if<std::is_integral<Integer>::value>::type>
627constexpr FixedPoint<I, F> operator>>(FixedPoint<I, F> lhs, Integer rhs) { 615constexpr FixedPoint<I, F> operator>>(FixedPoint<I, F> lhs, Integer rhs) {
628 lhs >>= rhs; 616 lhs >>= rhs;
629 return lhs; 617 return lhs;
630} 618}
631 619
632// comparison operators 620// comparison operators
633template <size_t I, size_t F, class Number, 621template <size_t I, size_t F, IsArithmetic Number>
634 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
635constexpr bool operator>(FixedPoint<I, F> lhs, Number rhs) { 622constexpr bool operator>(FixedPoint<I, F> lhs, Number rhs) {
636 return lhs > FixedPoint<I, F>(rhs); 623 return lhs > FixedPoint<I, F>(rhs);
637} 624}
638template <size_t I, size_t F, class Number, 625template <size_t I, size_t F, IsArithmetic Number>
639 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
640constexpr bool operator<(FixedPoint<I, F> lhs, Number rhs) { 626constexpr bool operator<(FixedPoint<I, F> lhs, Number rhs) {
641 return lhs < FixedPoint<I, F>(rhs); 627 return lhs < FixedPoint<I, F>(rhs);
642} 628}
643template <size_t I, size_t F, class Number, 629template <size_t I, size_t F, IsArithmetic Number>
644 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
645constexpr bool operator>=(FixedPoint<I, F> lhs, Number rhs) { 630constexpr bool operator>=(FixedPoint<I, F> lhs, Number rhs) {
646 return lhs >= FixedPoint<I, F>(rhs); 631 return lhs >= FixedPoint<I, F>(rhs);
647} 632}
648template <size_t I, size_t F, class Number, 633template <size_t I, size_t F, IsArithmetic Number>
649 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
650constexpr bool operator<=(FixedPoint<I, F> lhs, Number rhs) { 634constexpr bool operator<=(FixedPoint<I, F> lhs, Number rhs) {
651 return lhs <= FixedPoint<I, F>(rhs); 635 return lhs <= FixedPoint<I, F>(rhs);
652} 636}
653template <size_t I, size_t F, class Number, 637template <size_t I, size_t F, IsArithmetic Number>
654 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
655constexpr bool operator==(FixedPoint<I, F> lhs, Number rhs) { 638constexpr bool operator==(FixedPoint<I, F> lhs, Number rhs) {
656 return lhs == FixedPoint<I, F>(rhs); 639 return lhs == FixedPoint<I, F>(rhs);
657} 640}
658template <size_t I, size_t F, class Number, 641template <size_t I, size_t F, IsArithmetic Number>
659 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
660constexpr bool operator!=(FixedPoint<I, F> lhs, Number rhs) { 642constexpr bool operator!=(FixedPoint<I, F> lhs, Number rhs) {
661 return lhs != FixedPoint<I, F>(rhs); 643 return lhs != FixedPoint<I, F>(rhs);
662} 644}
663 645
664template <size_t I, size_t F, class Number, 646template <size_t I, size_t F, IsArithmetic Number>
665 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
666constexpr bool operator>(Number lhs, FixedPoint<I, F> rhs) { 647constexpr bool operator>(Number lhs, FixedPoint<I, F> rhs) {
667 return FixedPoint<I, F>(lhs) > rhs; 648 return FixedPoint<I, F>(lhs) > rhs;
668} 649}
669template <size_t I, size_t F, class Number, 650template <size_t I, size_t F, IsArithmetic Number>
670 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
671constexpr bool operator<(Number lhs, FixedPoint<I, F> rhs) { 651constexpr bool operator<(Number lhs, FixedPoint<I, F> rhs) {
672 return FixedPoint<I, F>(lhs) < rhs; 652 return FixedPoint<I, F>(lhs) < rhs;
673} 653}
674template <size_t I, size_t F, class Number, 654template <size_t I, size_t F, IsArithmetic Number>
675 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
676constexpr bool operator>=(Number lhs, FixedPoint<I, F> rhs) { 655constexpr bool operator>=(Number lhs, FixedPoint<I, F> rhs) {
677 return FixedPoint<I, F>(lhs) >= rhs; 656 return FixedPoint<I, F>(lhs) >= rhs;
678} 657}
679template <size_t I, size_t F, class Number, 658template <size_t I, size_t F, IsArithmetic Number>
680 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
681constexpr bool operator<=(Number lhs, FixedPoint<I, F> rhs) { 659constexpr bool operator<=(Number lhs, FixedPoint<I, F> rhs) {
682 return FixedPoint<I, F>(lhs) <= rhs; 660 return FixedPoint<I, F>(lhs) <= rhs;
683} 661}
684template <size_t I, size_t F, class Number, 662template <size_t I, size_t F, IsArithmetic Number>
685 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
686constexpr bool operator==(Number lhs, FixedPoint<I, F> rhs) { 663constexpr bool operator==(Number lhs, FixedPoint<I, F> rhs) {
687 return FixedPoint<I, F>(lhs) == rhs; 664 return FixedPoint<I, F>(lhs) == rhs;
688} 665}
689template <size_t I, size_t F, class Number, 666template <size_t I, size_t F, IsArithmetic Number>
690 class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
691constexpr bool operator!=(Number lhs, FixedPoint<I, F> rhs) { 667constexpr bool operator!=(Number lhs, FixedPoint<I, F> rhs) {
692 return FixedPoint<I, F>(lhs) != rhs; 668 return FixedPoint<I, F>(lhs) != rhs;
693} 669}