carl  24.04
Computer ARithmetic Library
operations.cpp
Go to the documentation of this file.
1 #include "../numbers.h"
2 
3 #include "parser.h"
4 
5 #include <limits>
6 
7 #include <boost/numeric/interval.hpp>
8 
9 #ifdef USE_CLN_NUMBERS
10 namespace carl
11 {
12  template<>
13  cln::cl_RA rationalize<cln::cl_RA>(double n) {
14  switch (std::fpclassify(n)) {
15  case FP_NORMAL: // normalized are fully supported
16  return cln::rationalize(convert<mpq_class, cln::cl_RA>(n));
17  case FP_SUBNORMAL: { // subnormals result in underflows, hence the value of the double is 0.f, where f is the significand precision
18  static_assert(sizeof(n) == 8, "double is assumed to be eight bytes wide.");
19  auto significandBits = reinterpret_cast<sint>(&n);
20  significandBits = (significandBits << 12) >> 12;
21  if( n < 0 )
22  significandBits = -significandBits;
23  return cln::cl_RA( significandBits ) * ONE_DIVIDED_BY_10_TO_THE_POWER_OF_52;
24  }
25  case FP_ZERO:
26  return 0;
27  case FP_NAN: // NaN and infinite are not supported
28  case FP_INFINITE:
29  assert(false);
30  break;
31  }
32  return 0;
33  }
34 
35  template<>
36  cln::cl_RA rationalize<cln::cl_RA>(float n)
37  {
38  switch (std::fpclassify(n))
39  {
40  case FP_NORMAL: // normalized are fully supported
41  return cln::rationalize(convert<mpq_class, cln::cl_RA>(n));
42  case FP_SUBNORMAL: { // subnormals result in underflows, hence the value of the double is 0.f, where f is the significand precision
43  static_assert(sizeof(n) == 4, "float is assumed to be four bytes wide.");
44  auto significandBits = reinterpret_cast<sint>(&n);
45  significandBits = (significandBits << 9) >> 9;
46  if( n < 0 )
47  significandBits = -significandBits;
48  return cln::cl_RA( significandBits ) * ONE_DIVIDED_BY_10_TO_THE_POWER_OF_23;
49  }
50  case FP_ZERO:
51  return 0;
52  case FP_NAN: // NaN and infinite are not supported
53  case FP_INFINITE:
54  assert(false);
55  break;
56  }
57  return 0;
58  }
59 
60  bool sqrt_exact(const cln::cl_RA& a, cln::cl_RA& b)
61  {
62  if( a < 0 ) return false;
63  return cln::sqrtp( a, &b );
64  }
65 
66  cln::cl_RA sqrt(const cln::cl_RA& a)
67  {
68  auto r = sqrt_safe(a);
69  return (r.first + r.second) / 2;
70  }
71 
72  cln::cl_RA scaleByPowerOfTwo(const cln::cl_RA& a, int exp) {
73  if (exp > 0) {
74  return cln::cl_RA(cln::numerator(a) << exp) / cln::denominator(a);
75  } else if (exp < 0) {
76  return cln::cl_RA(cln::numerator(a)) / (cln::denominator(a) << -exp);
77  }
78  return a;
79  }
80 
81  std::pair<cln::cl_RA, cln::cl_RA> sqrt_safe(const cln::cl_RA& a)
82  {
83  assert( a >= 0 );
84  cln::cl_RA exact_root;
85  if (cln::sqrtp(a, &exact_root)) {
86  // root can be computed exactly.
87  return std::make_pair(exact_root, exact_root);
88  } else {
89  auto factor = int(cln::integer_length(cln::denominator(a))) - int(cln::integer_length(cln::numerator(a)));
90  if (cln::oddp(factor)) factor += 1;
91  cln::cl_RA n = scaleByPowerOfTwo(a, factor);
92  double dn = to_double(n);
93  cln::cl_RA nra = cln::rationalize(dn);
94  boost::numeric::interval<double> i;
95  if (nra > n) {
96  i.assign(to_double(2*n-nra), dn);
97  assert(2*n-nra <= n);
98  } else {
99  i.assign(dn, to_double(2*n-nra));
100  assert(n <= 2*n-nra);
101  }
102  i = boost::numeric::sqrt(i);
103  i.assign(
104  std::nexttoward(i.lower(), -std::numeric_limits<double>::infinity()),
105  std::nexttoward(i.upper(), std::numeric_limits<double>::infinity())
106  );
107  factor = factor / 2;
108  cln::cl_RA lower = scaleByPowerOfTwo(cln::rationalize(i.lower()), -factor);
109  cln::cl_RA upper = scaleByPowerOfTwo(cln::rationalize(i.upper()), -factor);
110  assert(lower*lower <= a);
111  assert(a <= upper*upper);
112  return std::make_pair(lower, upper);
113  }
114  }
115 
116  std::pair<cln::cl_RA, cln::cl_RA> sqrt_fast(const cln::cl_RA& a)
117  {
118  assert(a >= 0);
119  cln::cl_RA exact_root;
120  if (cln::sqrtp(a, &exact_root)) {
121  // root can be computed exactly.
122  return std::make_pair(exact_root, exact_root);
123  } else {
124  // compute an approximation with sqrt(). we can assume that the surrounding integers contain the actual root.
125  //auto factor = cln::integer_length(cln::denominator(a)) - cln::integer_length(cln::numerator(a));
126  //if (cln::oddp(factor)) factor += 1;
127  cln::cl_I lower = cln::floor1(cln::sqrt(to_lf(a)));
128  cln::cl_I upper = lower + 1;
129  assert(cln::expt_pos(lower,2) < a);
130  assert(cln::expt_pos(upper,2) > a);
131  return std::make_pair(lower, upper);
132  }
133  }
134 
135  std::pair<cln::cl_RA, cln::cl_RA> root_safe(const cln::cl_RA& a, uint n) {
136  auto res = cln::realpart(cln::expt(a, cln::cl_RA(1)/n));
137  return std::make_pair(cln::cl_RA(cln::floor1(res)), cln::cl_RA(cln::ceiling1(res)));
138  }
139 
140  template<>
141  cln::cl_I parse<cln::cl_I>(const std::string& n) {
142  cln::cl_I res;
143  bool success = parser::parseDecimal(n, res);
144  assert(success);
145  return res;
146  }
147 
148  template<>
149  bool try_parse<cln::cl_I>(const std::string& n, cln::cl_I& res) {
150  return parser::parseDecimal(n, res);
151  }
152 
153  template<>
154  cln::cl_RA parse<cln::cl_RA>(const std::string& n) {
155  cln::cl_RA res;
156  bool success = parser::parseRational(n, res);
157  assert(success);
158  return res;
159  }
160 
161  template<>
162  bool try_parse<cln::cl_RA>(const std::string& n, cln::cl_RA& res) {
163  return parser::parseRational(n, res);
164  }
165 
166  std::string toString(const cln::cl_RA& _number, bool _infix)
167  {
168  std::stringstream s;
169  bool negative = (_number < cln::cl_RA(0));
170  if(negative) s << "(-" << (_infix ? "" : " ");
171  if(_infix) s << carl::abs(_number);
172  else
173  {
174  cln::cl_I d = carl::get_denom(_number);
175  if(d != cln::cl_I(1)) s << "(/ " << carl::abs(carl::get_num(_number)) << " " << carl::abs(d) << ")";
176  else s << carl::abs(_number);
177  }
178  if(negative)
179  s << ")";
180  return s.str();
181  }
182 
183  std::string toString(const cln::cl_I& _number, bool _infix)
184  {
185  std::stringstream s;
186  bool negative = (_number < cln::cl_I(0));
187  if(negative) s << "(-" << (_infix ? "" : " ");
188  s << carl::abs(_number);
189  if(negative)
190  s << ")";
191  return s.str();
192  }
193 }
194 #endif
carl is the main namespace for the library.
T rationalize(const PreventConversion< mpq_class > &)
std::uint64_t uint
Definition: numbers.h:16
std::pair< cln::cl_RA, cln::cl_RA > sqrt_fast(const cln::cl_RA &a)
Compute square root in a fast but less precise way.
std::string toString(Relation r)
Definition: Relation.h:73
Interval< Number > abs(const Interval< Number > &_in)
Method which returns the absolute value of the passed number.
Definition: Interval.h:1511
bool sqrt_exact(const cln::cl_RA &a, cln::cl_RA &b)
Calculate the square root of a fraction if possible.
static const cln::cl_RA ONE_DIVIDED_BY_10_TO_THE_POWER_OF_23
Definition: operations.h:196
std::pair< cln::cl_RA, cln::cl_RA > root_safe(const cln::cl_RA &a, uint n)
Interval< Number > exp(const Interval< Number > &i)
Definition: Exponential.h:10
mpq_class sqrt(const mpq_class &a)
Definition: operations.cpp:34
cln::cl_I get_num(const cln::cl_RA &n)
Extract the numerator from a fraction.
Definition: operations.h:60
Interval< Number > sqrt(const Interval< Number > &i)
Definition: Power.h:51
cln::cl_LF to_lf(const cln::cl_RA &n)
Convert a cln fraction to a cln long float.
Definition: operations.h:192
static const cln::cl_RA ONE_DIVIDED_BY_10_TO_THE_POWER_OF_52
Definition: operations.h:197
cln::cl_I get_denom(const cln::cl_RA &n)
Extract the denominator from a fraction.
Definition: operations.h:69
double to_double(const cln::cl_RA &n)
Converts the given fraction to a double.
Definition: operations.h:113
std::int64_t sint
Definition: numbers.h:17
std::pair< cln::cl_RA, cln::cl_RA > sqrt_safe(const cln::cl_RA &a)
Calculate the square root of a fraction.
bool parseDecimal(const std::string &input, T &output)
Definition: parser.h:146
bool parseRational(const std::string &input, T &output)
Definition: parser.h:150