1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3 
4   Copyright (C) 1997--2021 Han-Wen Nienhuys <hanwen@xs4all.nl>
5 
6   LilyPond is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10 
11   LilyPond is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15 
16   You should have received a copy of the GNU General Public License
17   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #ifndef RATIONAL_HH
21 #define RATIONAL_HH
22 
23 #include "compare.hh"
24 #include "flower-proto.hh"
25 #include "std-string.hh"
26 #include <limits.h>
27 
28 /**
29    Rational numbers.  Included is support for + and - infinity.
30 */
31 class Rational
32 {
33   /**
34      Sign of rational.
35      -2, .. 2
36 
37      -2,2 is - and + infinity.
38      -1,1 is negative and positive.
39      0 if *this is zero.
40   */
41   int sign_;
42   U64 num_, den_;
43 
44 private:
45   // n.b. can be used to intialize abnormally
Rational(int sign,U64 num,U64 den)46   constexpr Rational (int sign, U64 num, U64 den)
47     : sign_ (sign), num_ (num), den_ (den)
48   {
49   }
50 
51   void normalize ();
52 
53 public:
numerator() const54   I64 numerator () const { return sign_ * static_cast<I64> (num_); }
denominator() const55   I64 denominator () const { return static_cast<I64> (den_); }
num() const56   I64 num () const { return numerator (); }
den() const57   I64 den () const { return denominator (); }
58 
59   // n.b. not valid for infinities
60   I64 trunc_int () const;
61   Rational trunc_rat () const;
62   Rational div_rat (Rational) const;
63   Rational mod_rat (Rational) const;
64   Rational abs () const;
65   void negate ();
66 
operator bool() const67   explicit operator bool () const { return sign_ != 0; }
68   explicit operator double () const;
69 
operator -() const70   constexpr Rational operator - () const { return { -sign_, num_, den_ }; }
71 
72   // default to zero
Rational()73   constexpr Rational () : sign_ (0), num_ (1), den_ (1) {}
74 
75   // positive infinity
infinity()76   static constexpr Rational infinity () { return { 2, 1, 1 }; }
77 
78   // not-a-number
nan()79   static constexpr Rational nan () { return { 1, 0, 0 }; }
80 
81   // Allow implicit conversion from integer.  All of these must be defined or
82   // deleted to avoid ambiguity.  "long long" is specified by the C++ standard
83   // to be at least 64 bits wide, which is what we are storing.
Rational(int n)84   Rational (int n) : Rational (static_cast<long long> (n)) {}
Rational(long n)85   Rational (long n) : Rational (static_cast<long long> (n)) {}
86   Rational (long long n);
Rational(unsigned n)87   Rational (unsigned n) : Rational (static_cast<unsigned long long> (n)) {}
Rational(unsigned long n)88   Rational (unsigned long n) : Rational (static_cast<unsigned long long> (n)) {}
89   Rational (unsigned long long);
90 
91   // n.b. {0, 0} is treated as zero rather than NaN
92   explicit Rational (I64, I64);
93 
94   explicit Rational (double);
95   Rational (Rational const &r) = default;
96   Rational &operator = (Rational const &r) = default;
97 
98   Rational &operator *= (Rational);
99   Rational &operator /= (Rational);
100   Rational &operator += (Rational);
101   Rational &operator -= (Rational);
102   Rational &operator %= (Rational);
103   static int compare (Rational const &, Rational const &);
104   int sign () const;
105   std::string to_string () const;
106 
107   // false for positive infinity, negative infinity, or not-a-number
isfinite(Rational const & r)108   friend bool isfinite (Rational const &r) { return r.den_ && !isinf (r); }
109 
110   // true for positive or negative infinity
isinf(Rational const & r)111   friend bool isinf (Rational const &r) { return r.sign_ / 2; }
112 
113   // true for not-a-number
isnan(Rational const & r)114   friend bool isnan (Rational const &r) { return !r.den_; }
115 };
116 
117 #include "arithmetic-operator.hh"
118 
119 IMPLEMENT_ARITHMETIC_OPERATOR (Rational, / );
120 IMPLEMENT_ARITHMETIC_OPERATOR (Rational, +);
121 IMPLEMENT_ARITHMETIC_OPERATOR (Rational, *);
122 IMPLEMENT_ARITHMETIC_OPERATOR (Rational, -);
123 IMPLEMENT_ARITHMETIC_OPERATOR (Rational, % );
124 
125 INSTANTIATE_COMPARE (Rational const &, Rational::compare);
126 
127 int compare (Rational const &, Rational const &);
128 int sign (Rational r);
129 
130 inline std::string
to_string(Rational const & r)131 to_string (Rational const &r)
132 {
133   return r.to_string ();
134 }
135 
136 #endif // RATIONAL_HH
137