bpp-phyl3  3.0.0
ExtendedFloat.h
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: The Bio++ Development Group
2 //
3 // SPDX-License-Identifier: CECILL-2.1
4 
5 #ifndef BPP_PHYL_LIKELIHOOD_DATAFLOW_EXTENDEDFLOAT_H
6 #define BPP_PHYL_LIKELIHOOD_DATAFLOW_EXTENDEDFLOAT_H
7 
8 #include <Bpp/Exceptions.h>
9 #include <Eigen/Core>
10 #include <cmath>
11 #include <iostream>
12 #include <limits>
13 #include <string>
14 
15 
16 namespace bpp
17 {
18 template<typename T> constexpr T constexpr_power (T d, int n)
19 {
20  return n == 0 ? 1.0 : (n > 0 ? constexpr_power (d, n - 1) * d : constexpr_power (d, n + 1) / d);
21 }
22 
23 // Compute power of integers
24 inline int powi (int base, unsigned int exp)
25 {
26  int res = 1;
27  while (exp)
28  {
29  if (exp & 1)
30  res *= base;
31  exp >>= 1;
32  base *= base;
33  }
34  return res;
35 }
36 
38 {
39  // Assumes positive integer
40 
41 public:
42  using FloatType = double;
43  using ExtType = int;
44 
45  // Parameter: decide how much product we can do safely before having to normalize (smaller -> less normalizations)
46  static constexpr int allowed_product_without_normalization = 2;
47 
48  // Radix is the float exponent base
49  static constexpr int radix = std::numeric_limits<FloatType>::radix;
50 
51  const static double ln_radix;
52 
53  // biggest_repr_radix_power = max { n ; radix^n is representable }
54  static constexpr int biggest_repr_radix_power = std::numeric_limits<FloatType>::max_exponent - 1;
55 
56  // biggest_normalized_radix_power = max { n ; (radix^n)^allowed_product_without_normalization is representable }
57  static constexpr int biggest_normalized_radix_power =
59 
60 
61  // biggest_normalized_value = max { f ; f^allowed_product_without_normalization is representable }
64 
65  // smallest_repr_radix_power = min { n ; radix^n is representable }
66  static constexpr int smallest_repr_radix_power = std::numeric_limits<FloatType>::min_exponent + 1;
67 
68  // smallest_normalized_radix_power = min { n ; (radix^n)^allowed_product_denorm is representable }
69  static constexpr int smallest_normalized_radix_power =
71 
72  // smallest_normalized_value = min { f ; f^allowed_product_denorm is representable }
75 
76  // factors to scale f_ to renormalize.
79 
80  // TODO add denorm info for sum
81 
82  constexpr ExtendedFloat (FloatType f = 0.0, ExtType e = 0) noexcept : f_ (f), exp_ (e)
83  {}
84 
85  ExtendedFloat (const ExtendedFloat& ef) noexcept : f_ (ef.f_), exp_ (ef.exp_)
86  {}
87 
88  const FloatType& float_part () const noexcept { return f_; }
89  const ExtType& exponent_part () const noexcept { return exp_; }
90 
91  bool normalize_big () noexcept
92  {
93  if (std::isfinite (f_))
94  {
95  bool normalized = false;
97  {
98  f_ *= (double)normalize_big_factor;
100  normalized = true;
101  }
102  return normalized;
103  }
104  return false;
105  }
106 
108  {
109  if (f_ != 0)
110  {
111  bool normalized = false;
113  {
114  f_ *= (double)normalize_small_factor;
116  normalized = true;
117  }
118  return normalized;
119  }
120  return false;
121  }
122 
123  void normalize () noexcept
124  {
125  if (!normalize_big())
126  {
127  normalize_small();
128  }
129  }
130 
131  // Static methods without normalization
132  inline static ExtendedFloat denorm_mul (const ExtendedFloat& lhs, const ExtendedFloat& rhs)
133  {
134  return {lhs.float_part () * rhs.float_part (), lhs.exponent_part () + rhs.exponent_part ()};
135  }
136 
137  inline static ExtendedFloat denorm_div (const ExtendedFloat& lhs, const ExtendedFloat& rhs)
138  {
139  return {lhs.float_part () / rhs.float_part (), lhs.exponent_part () - rhs.exponent_part ()};
140  }
141 
142  inline static ExtendedFloat denorm_add (const ExtendedFloat& lhs, const ExtendedFloat& rhs)
143  {
144  return (lhs.exponent_part () >= rhs.exponent_part ()) ?
145  ExtendedFloat(lhs.float_part () + rhs.float_part () * constexpr_power<double>(ExtendedFloat::radix, rhs.exponent_part () - lhs.exponent_part ()), lhs.exponent_part ()) :
146  ExtendedFloat(rhs.float_part () + lhs.float_part () * constexpr_power<double>(ExtendedFloat::radix, lhs.exponent_part () - rhs.exponent_part ()), rhs.exponent_part ());
147  }
148 
149  inline static ExtendedFloat denorm_sub (const ExtendedFloat& lhs, const ExtendedFloat& rhs)
150  {
151  return (lhs.exponent_part () >= rhs.exponent_part ()) ?
152  ExtendedFloat(lhs.float_part () - rhs.float_part () * constexpr_power<double>(ExtendedFloat::radix, rhs.exponent_part () - lhs.exponent_part ()), lhs.exponent_part ()) :
153  ExtendedFloat(rhs.float_part () - lhs.float_part () * constexpr_power<double>(ExtendedFloat::radix, lhs.exponent_part () - rhs.exponent_part ()), rhs.exponent_part ());
154  }
155 
156  inline static ExtendedFloat denorm_sub (const ExtendedFloat& lhs, const double& rhs)
157  {
158  return (lhs.exponent_part () >= 0) ?
159  ExtendedFloat(lhs.float_part () - rhs * constexpr_power<double>(ExtendedFloat::radix, -lhs.exponent_part ()), lhs.exponent_part ()) :
160  ExtendedFloat(rhs - lhs.float_part () * constexpr_power<double>(ExtendedFloat::radix, lhs.exponent_part ()), 0);
161  }
162 
163  inline static ExtendedFloat denorm_pow (const ExtendedFloat& lhs, double exp)
164  {
165  double b = lhs.exponent_part() * exp;
168  return r;
169  }
170 
171  inline static ExtendedFloat denorm_pow (const ExtendedFloat& lhs, int exp)
172  {
173  if (exp == 0)
174  return ExtendedFloat(1.0);
175  if (exp & 1)
176  return exp > 0 ? denorm_mul(lhs, denorm_pow(lhs, exp - 1)) : denorm_div(denorm_pow(lhs, exp + 1), lhs);
177  else
178  {
179  ExtendedFloat r2(std::pow(lhs.float_part(), 2));
180  r2.normalize();
181  auto r2k = denorm_pow(r2, exp >> 1);
182  r2k.normalize();
183  ExtendedFloat r(r2k.float_part(), r2k.exponent_part() + lhs.exponent_part() * exp);
184  return r;
185  }
186  }
187 
188 
189  /*********************************
190  ** Utilities
191  *********************************/
193  {
194  f_ = ef.float_part();
195  exp_ = ef.exponent_part();
196  return *this;
197  }
198 
199  inline ExtendedFloat operator+(const ExtendedFloat& rhs) const
200  {
201  auto r = denorm_add (*this, rhs);
202  r.normalize ();
203  return r;
204  }
205 
206  inline ExtendedFloat operator-(const ExtendedFloat& rhs) const
207  {
208  auto r = denorm_sub (*this, rhs);
209  r.normalize ();
210  return r;
211  }
212 
213  template<typename F, typename = typename std::enable_if<std::is_arithmetic<F>::value>::type>
214  inline ExtendedFloat operator-(const F& rhs) const
215  {
216  auto r = denorm_sub (*this, rhs);
217 // r.normalize ();
218  return r;
219  }
220 
221  inline ExtendedFloat operator*(const ExtendedFloat& rhs) const
222  {
223  auto r = denorm_mul (*this, rhs);
224  r.normalize ();
225  return r;
226  }
227 
228  template<typename F, typename = typename std::enable_if<std::is_arithmetic<F>::value>::type>
229  inline ExtendedFloat operator*(const F& rhs) const
230  {
231  ExtendedFloat r(float_part () * rhs, exponent_part ());
232  r.normalize ();
233  return r;
234  }
235 
236  inline ExtendedFloat operator/(const ExtendedFloat& rhs) const
237  {
238  auto r = denorm_div (*this, rhs);
239  r.normalize ();
240  return r;
241  }
242 
244  {
245  float_part () *= rhs.float_part ();
246  exponent_part () += rhs.exponent_part ();
247  normalize();
248  return *this;
249  }
250 
252  {
253  float_part () /= rhs.float_part ();
254  exponent_part () -= rhs.exponent_part ();
255  normalize();
256  return *this;
257  }
258 
260  {
261  if (exponent_part () >= rhs.exponent_part ())
262  {
263  float_part() += rhs.float_part () * constexpr_power<double>(ExtendedFloat::radix, rhs.exponent_part () - exponent_part ());
264  }
265  else
266  {
267  float_part() = rhs.float_part () + float_part () * constexpr_power<double>(ExtendedFloat::radix, exponent_part () - rhs.exponent_part ());
268  exponent_part() = rhs.exponent_part ();
269  }
270  normalize ();
271  return *this;
272  }
273 
275  {
276  if (exponent_part () >= rhs.exponent_part ())
277  {
278  float_part() -= rhs.float_part () * constexpr_power<double>(ExtendedFloat::radix, rhs.exponent_part () - exponent_part ());
279  }
280  else
281  {
282  float_part() = rhs.float_part () - float_part () * constexpr_power<double>(ExtendedFloat::radix, exponent_part () - rhs.exponent_part ());
283  exponent_part() = rhs.exponent_part ();
284  }
285  normalize ();
286  return *this;
287  }
288 
289  inline ExtendedFloat operator-() const
290  {
291  return ExtendedFloat(-float_part(), exponent_part());
292  }
293 
294  inline ExtendedFloat pow (double exp) const
295  {
296  auto r = denorm_pow(*this, exp);
297  r.normalize ();
298  return r;
299  }
300 
301  inline ExtendedFloat pow (int exp) const
302  {
303  auto r = denorm_pow(*this, exp);
304  r.normalize ();
305  return r;
306  }
307 
308  /*
309  * Tests
310  *
311  */
312  inline bool operator==(const ExtendedFloat& rhs) const
313  {
314  return float_part() == rhs.float_part() && exponent_part() == rhs.exponent_part();
315  }
316 
317  inline bool operator!=(const ExtendedFloat& rhs) const
318  {
319  return float_part() != rhs.float_part() || exponent_part() != rhs.exponent_part();
320  }
321 
322  inline bool operator<(const ExtendedFloat& rhs) const
323  {
324  return exponent_part() < rhs.exponent_part() || (exponent_part() == rhs.exponent_part() && float_part() < rhs.float_part());
325  }
326 
327  inline bool operator<=(const ExtendedFloat& rhs) const
328  {
329  return exponent_part() < rhs.exponent_part() || (exponent_part() == rhs.exponent_part() && float_part() <= rhs.float_part());
330  }
331 
332  inline bool operator>=(const ExtendedFloat& rhs) const
333  {
334  return exponent_part() > rhs.exponent_part() || (exponent_part() == rhs.exponent_part() && float_part() >= rhs.float_part());
335  }
336 
337  inline bool operator>=(const double& rhs) const
338  {
339  return convert(*this) >= rhs;
340  }
341 
342  inline bool operator>(const ExtendedFloat& rhs) const
343  {
344  return exponent_part() > rhs.exponent_part() || (exponent_part() == rhs.exponent_part() && float_part() > rhs.float_part());
345  }
346 
347  inline bool operator>(const double& rhs) const
348  {
349  return convert(*this) > rhs;
350  }
351 
352  inline double log () const
353  {
354  return std::log (float_part ()) + static_cast<double>(exponent_part ()) * ln_radix;
355  }
356 
357  inline ExtendedFloat abs () const
358  {
360  }
361 
362  // Compute lround, and return tuple <lround, remainder>
363  inline std::tuple<int, double> lround() const
364  {
365  throw Exception("ExtendedFloat::lround need to be checked.");
366  auto c = float_part ();
367  auto b = exponent_part();
368  if (b <= 0)
369  {
370  double t = convert(*this);
371  auto d = std::lround(t);
372  return std::tuple<int, double>{d, remainder(t, 1)};
373  }
374  if (b > 0)
375  {
376  long long res(0);
377  while (b > 0)
378  {
379  auto lrc = std::lround(c);
380  res += lrc * powi(radix, uint(b));
381  c -= (double)lrc;
384  }
385  auto t = c * constexpr_power<double>(radix, b);
386  auto it = std::lround(t);
387  return std::tuple<int, double>{res + it, remainder(t, 1)};
388  }
389  }
390 
391 
392  // exp(a.r^b)=r^(a/log(r) * r^b) = r^(c * r^b) = r^([c * r^b]) * r^(c * r^b - [c * r^b])
393  // with c=a/log(r)
394 
395  inline ExtendedFloat exp () const
396  {
397  auto c = float_part () / ln_radix;
398  auto ef = ExtendedFloat(c, exponent_part());
399  auto u = ef.lround();
400  return ExtendedFloat(std::pow(radix, std::get<1>(u)), (int)std::get<0>(u));
401  }
402 
403  /*************/
404  /* Dirty trick to allow for Eigen::Nullary_wrapers output only the float part, for ExtendedFloatEigen */
405 
406 private:
407  /* Necessary to keep this private to prevent misuse */
408  operator double() const
409  {
410  return float_part();
411  }
412 
413  template<typename Scalar, typename NullaryOp, bool has_nullary, bool has_unary, bool has_binary>
415 
416 public:
417  // !!! no check on the validation of the conversion
418  static inline double convert(const ExtendedFloat& ef)
419  {
420  return ef.float_part () * constexpr_power<double>(ExtendedFloat::radix, ef.exponent_part ());
421  }
422 
423 protected:
426 
427  FloatType& float_part () noexcept { return f_; }
428  ExtType& exponent_part () noexcept { return exp_; }
429 };
430 
431 inline std::ostream& operator<<(std::ostream& os, const ExtendedFloat& ef)
432 {
433  os << ef.float_part () << " * 2^" << ef.exponent_part ();
434  return os;
435 }
436 
437 inline std::string to_string (const ExtendedFloat& ef)
438 {
439  using std::to_string;
440  return "double(" + to_string (ef.float_part ()) + " * 2^" + to_string (ef.exponent_part ()) + ")";
441 }
442 
443 inline double log (const ExtendedFloat& ef)
444 {
445  return ef.log();
446 }
447 
448 inline ExtendedFloat operator*(const double& lhs, const ExtendedFloat& rhs)
449 {
450  return rhs * lhs;
451 }
452 
453 inline ExtendedFloat operator-(const double& lhs, const ExtendedFloat& rhs)
454 {
455  return rhs.ExtendedFloat::operator+(-lhs);
456 }
457 
458 inline ExtendedFloat operator+(const double& lhs, const ExtendedFloat& rhs)
459 {
460  return rhs.ExtendedFloat::operator+(lhs);
461 }
462 
463 inline ExtendedFloat operator/(const double& lhs, const ExtendedFloat& rhs)
464 {
465  return rhs * (1 / lhs);
466 }
467 
468 
469 inline ExtendedFloat pow (const ExtendedFloat& ef, double exp)
470 {
471  return ef.pow(exp);
472 }
473 
474 inline ExtendedFloat exp (const ExtendedFloat& ef)
475 {
476  return ef.exp();
477 }
478 
479 inline ExtendedFloat abs (const ExtendedFloat& ef)
480 {
481  return ef.abs();
482 }
483 
484 
485 // !!! no check on the validation of the conversion
486 inline double convert(const bpp::ExtendedFloat& ef)
487 {
488  return ef.float_part () * bpp::constexpr_power<double>(bpp::ExtendedFloat::radix, ef.exponent_part ());
489 }
490 } // namespace bpp
491 
492 
493 /*
494  * Storing ExtendedFloat in Eigen objects
495  *
496  */
497 
498 
499 namespace Eigen
500 {
501 template<>
502 struct NumTraits<bpp::ExtendedFloat> :
503  NumTraits<double> // permits to get the epsilon, dummy_precision, lowest, highest functions
504 {
508  enum
509  {
510  IsComplex = 0,
511  IsInteger = 0,
512  IsSigned = 1,
513  RequireInitialization = 1,
514  ReadCost = 1,
515  AddCost = 3,
516  MulCost = 2
517  };
518 };
519 template<typename BinaryOp>
520 struct ScalarBinaryOpTraits<bpp::ExtendedFloat, double, BinaryOp> { typedef bpp::ExtendedFloat ReturnType; };
521 
522 template<typename BinaryOp>
523 struct ScalarBinaryOpTraits<double, bpp::ExtendedFloat, BinaryOp> { typedef bpp::ExtendedFloat ReturnType; };
524 }
525 #endif // BPP_PHYL_LIKELIHOOD_DATAFLOW_EXTENDEDFLOAT_H
ExtendedFloat operator-() const
static ExtendedFloat denorm_pow(const ExtendedFloat &lhs, double exp)
bool operator!=(const ExtendedFloat &rhs) const
double log() const
static ExtendedFloat denorm_sub(const ExtendedFloat &lhs, const double &rhs)
ExtendedFloat pow(double exp) const
static constexpr int smallest_repr_radix_power
Definition: ExtendedFloat.h:66
ExtendedFloat operator*(const F &rhs) const
void normalize() noexcept
ExtendedFloat pow(int exp) const
ExtendedFloat & operator-=(const ExtendedFloat &rhs)
static const double ln_radix
Definition: ExtendedFloat.h:51
static ExtendedFloat denorm_add(const ExtendedFloat &lhs, const ExtendedFloat &rhs)
bool operator<=(const ExtendedFloat &rhs) const
ExtendedFloat & operator=(const ExtendedFloat &ef)
static ExtendedFloat denorm_pow(const ExtendedFloat &lhs, int exp)
ExtendedFloat & operator+=(const ExtendedFloat &rhs)
bool operator==(const ExtendedFloat &rhs) const
static ExtendedFloat denorm_div(const ExtendedFloat &lhs, const ExtendedFloat &rhs)
constexpr ExtendedFloat(FloatType f=0.0, ExtType e=0) noexcept
Definition: ExtendedFloat.h:82
ExtendedFloat operator-(const ExtendedFloat &rhs) const
static constexpr FloatType normalize_big_factor
Definition: ExtendedFloat.h:77
ExtendedFloat abs() const
static constexpr int allowed_product_without_normalization
Definition: ExtendedFloat.h:46
std::tuple< int, double > lround() const
ExtendedFloat operator-(const F &rhs) const
static ExtendedFloat denorm_mul(const ExtendedFloat &lhs, const ExtendedFloat &rhs)
static ExtendedFloat denorm_sub(const ExtendedFloat &lhs, const ExtendedFloat &rhs)
static constexpr FloatType smallest_normalized_value
Definition: ExtendedFloat.h:73
ExtendedFloat & operator*=(const ExtendedFloat &rhs)
bool operator>=(const double &rhs) const
static constexpr FloatType normalize_small_factor
Definition: ExtendedFloat.h:78
bool operator>=(const ExtendedFloat &rhs) const
ExtType & exponent_part() noexcept
const FloatType & float_part() const noexcept
Definition: ExtendedFloat.h:88
const ExtType & exponent_part() const noexcept
Definition: ExtendedFloat.h:89
ExtendedFloat operator/(const ExtendedFloat &rhs) const
bool operator>(const ExtendedFloat &rhs) const
ExtendedFloat & operator/=(const ExtendedFloat &rhs)
friend struct Eigen::internal::nullary_wrapper
ExtendedFloat exp() const
ExtendedFloat operator*(const ExtendedFloat &rhs) const
bool operator<(const ExtendedFloat &rhs) const
static constexpr FloatType biggest_normalized_value
Definition: ExtendedFloat.h:62
static double convert(const ExtendedFloat &ef)
ExtendedFloat(const ExtendedFloat &ef) noexcept
Definition: ExtendedFloat.h:85
static constexpr int biggest_normalized_radix_power
Definition: ExtendedFloat.h:57
static constexpr int smallest_normalized_radix_power
Definition: ExtendedFloat.h:69
bool normalize_big() noexcept
Definition: ExtendedFloat.h:91
static constexpr int radix
Definition: ExtendedFloat.h:49
FloatType & float_part() noexcept
bool operator>(const double &rhs) const
static constexpr int biggest_repr_radix_power
Definition: ExtendedFloat.h:54
ExtendedFloat operator+(const ExtendedFloat &rhs) const
Defines the basic types of data flow nodes.
double log(const ExtendedFloat &ef)
ExtendedFloat exp(const ExtendedFloat &ef)
int powi(int base, unsigned int exp)
Definition: ExtendedFloat.h:24
std::vector< T > operator-(const std::vector< T > &v1, const std::vector< T > &v2)
std::string to_string(const ExtendedFloat &ef)
std::string to_string(const NoDimension &)
ExtendedFloat pow(const ExtendedFloat &ef, double exp)
std::vector< T > operator*(const std::vector< T > &v1, const std::vector< T > &v2)
std::vector< T > operator+(const std::vector< T > &v1, const std::vector< T > &v2)
std::vector< T > operator/(const std::vector< T > &v1, const std::vector< T > &v2)
double convert(const bpp::ExtendedFloat &ef)
std::ostream & operator<<(std::ostream &out, const BppBoolean &s)
ExtendedFloat abs(const ExtendedFloat &ef)
constexpr T constexpr_power(T d, int n)
Definition: ExtendedFloat.h:18