Lumiera  0.pre.03
»edit your freedom«
rational.hpp
Go to the documentation of this file.
1 /*
2  RATIONAL.hpp - support for precise rational arithmetics
3 
4  Copyright (C) Lumiera.org
5  2022, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 */
22 
23 
67 #ifndef LIB_RATIONAL_H
68 #define LIB_RATIONAL_H
69 
70 
71 #include "lib/integral.hpp"
72 #include "lib/util-quant.hpp"
73 
74 #include <cmath>
75 #include <limits>
76 #include <stdint.h>
77 #include <boost/rational.hpp>
78 
79 
80 namespace util {
81 
82  using Rat = boost::rational<int64_t>;
83  using boost::rational_cast;
84  using std::abs;
85 
86 
87 
88  inline bool
89  can_represent_Product (int64_t a, int64_t b)
90  {
91  return ilog2(abs(a))+1
92  + ilog2(abs(b))+1
93  < 63;
94  }
95 
96  inline bool
97  can_represent_Product (Rat a, Rat b)
98  {
99  return can_represent_Product(a.numerator(), b.numerator())
100  and can_represent_Product(a.denominator(), b.denominator());
101  }
102 
103  inline bool
104  can_represent_Sum (Rat a, Rat b)
105  {
106  return can_represent_Product(a.numerator(), b.denominator())
107  and can_represent_Product(b.numerator(), a.denominator());
108  }
109 
110 
128  inline int64_t
129  reQuant (int64_t num, int64_t den, int64_t u)
130  {
131  u = 0!=u? u:1;
132  auto [d,r] = util::iDiv (num, den);
133  // round to smallest integer fraction, to shake off "number dust"
134  f128 const ROUND_ULP = 1 + 1/(f128(std::numeric_limits<int64_t>::max()) * 2);
135 
136  // construct approximation quantised to 1/u
137  f128 frac = f128(r) / den;
138  int64_t res = d*u + int64_t(frac*u * ROUND_ULP);
139  ENSURE (abs (f128(res)/u - rational_cast<f128>(Rat{num,den})) <= 1.0/abs(u)
140  ,"Requantisation error exceeded num=%li / den=%li -> res=%li / quant=%li"
141  , num, den, res, u);
142  return res;
143  }
144 
158  inline Rat
159  reQuant (Rat src, int64_t u)
160  {
161  return Rat{reQuant (src.numerator(), src.denominator(), u), u};
162  }
163 } // namespace util
164 
165 
166 
173 inline util::Rat
174 operator""_r (unsigned long long num)
175 {
176  return util::Rat{num};
177 }
178 
179 
180 #endif /*LIB_RATIONAL_H*/
int64_t reQuant(int64_t num, int64_t den, int64_t u)
Re-Quantise a number into a new grid, truncating to the next lower grid point.
Definition: rational.hpp:129
Utilities for quantisation (grid alignment) and comparisons.
IDiv< I > iDiv(I num, I den)
Definition: util-quant.hpp:84
constexpr int ilog2(I num)
Integral binary logarithm (disregarding fractional part)
Definition: util-quant.hpp:180