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)
5  2022, Hermann Vosseler <Ichthyostega@web.de>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 */
13 
14 
58 #ifndef LIB_RATIONAL_H
59 #define LIB_RATIONAL_H
60 
61 
62 #include "lib/integral.hpp"
63 #include "lib/util-quant.hpp"
64 
65 #include <cmath>
66 #include <limits>
67 #include <stdint.h>
68 #include <boost/rational.hpp>
69 
70 
71 namespace util {
72 
73  using Rat = boost::rational<int64_t>;
74  using boost::rational_cast;
75  using std::abs;
76 
77 
78 
79  inline bool
80  can_represent_Product (int64_t a, int64_t b)
81  {
82  return ilog2(abs(a))+1
83  + ilog2(abs(b))+1
84  < 63;
85  }
86 
87  inline bool
88  can_represent_Product (Rat a, Rat b)
89  {
90  return can_represent_Product(a.numerator(), b.numerator())
91  and can_represent_Product(a.denominator(), b.denominator());
92  }
93 
94  inline bool
95  can_represent_Sum (Rat a, Rat b)
96  {
97  return can_represent_Product(a.numerator(), b.denominator())
98  and can_represent_Product(b.numerator(), a.denominator());
99  }
100 
101 
119  inline int64_t
120  reQuant (int64_t num, int64_t den, int64_t u)
121  {
122  u = 0!=u? u:1;
123  auto [d,r] = util::iDiv (num, den);
124  // round to smallest integer fraction, to shake off "number dust"
125  f128 const ROUND_ULP = 1 + 1/(f128(std::numeric_limits<int64_t>::max()) * 2);
126 
127  // construct approximation quantised to 1/u
128  f128 frac = f128(r) / den;
129  int64_t res = d*u + int64_t(frac*u * ROUND_ULP);
130  ENSURE (abs (f128(res)/u - rational_cast<f128>(Rat{num,den})) <= 1.0/abs(u)
131  ,"Requantisation error exceeded num=%li / den=%li -> res=%li / quant=%li"
132  , num, den, res, u);
133  return res;
134  }
135 
149  inline Rat
150  reQuant (Rat src, int64_t u)
151  {
152  return Rat{reQuant (src.numerator(), src.denominator(), u), u};
153  }
154 } // namespace util
155 
156 
157 
164 inline util::Rat
165 operator""_r (ullong num)
166 {
167  return util::Rat{num};
168 }
169 
170 
171 #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:120
Utilities for quantisation (grid alignment) and comparisons.
IDiv< I > iDiv(I num, I den)
Definition: util-quant.hpp:82
constexpr int ilog2(I num)
Integral binary logarithm (disregarding fractional part)
Definition: util-quant.hpp:178