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
16namespace bpp
17{
18template<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
24inline 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
41public:
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 {
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
290 {
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
406private:
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
416public:
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
423protected:
426
427 FloatType& float_part () noexcept { return f_; }
428 ExtType& exponent_part () noexcept { return exp_; }
429};
430
431inline std::ostream& operator<<(std::ostream& os, const ExtendedFloat& ef)
432{
433 os << ef.float_part () << " * 2^" << ef.exponent_part ();
434 return os;
435}
436
437inline 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
443inline double log (const ExtendedFloat& ef)
444{
445 return ef.log();
446}
447
448inline ExtendedFloat operator*(const double& lhs, const ExtendedFloat& rhs)
449{
450 return rhs * lhs;
451}
452
453inline ExtendedFloat operator-(const double& lhs, const ExtendedFloat& rhs)
454{
455 return rhs.ExtendedFloat::operator+(-lhs);
456}
457
458inline ExtendedFloat operator+(const double& lhs, const ExtendedFloat& rhs)
459{
460 return rhs.ExtendedFloat::operator+(lhs);
461}
462
463inline ExtendedFloat operator/(const double& lhs, const ExtendedFloat& rhs)
464{
465 return rhs * (1 / lhs);
466}
467
468
469inline ExtendedFloat pow (const ExtendedFloat& ef, double exp)
470{
471 return ef.pow(exp);
472}
473
475{
476 return ef.exp();
477}
478
480{
481 return ef.abs();
482}
483
484
485// !!! no check on the validation of the conversion
486inline 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
499namespace Eigen
500{
501template<>
502struct 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};
519template<typename BinaryOp>
520struct ScalarBinaryOpTraits<bpp::ExtendedFloat, double, BinaryOp> { typedef bpp::ExtendedFloat ReturnType; };
521
522template<typename BinaryOp>
523struct 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)
ExtType & exponent_part() noexcept
std::tuple< int, double > lround() const
ExtendedFloat & operator-=(const ExtendedFloat &rhs)
const ExtType & exponent_part() const noexcept
Definition: ExtendedFloat.h:89
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 &ef)
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
static ExtendedFloat denorm_pow(const ExtendedFloat &lhs, int exp)
const FloatType & float_part() const noexcept
Definition: ExtendedFloat.h:88
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
ExtendedFloat operator-(const F &rhs) const
static ExtendedFloat denorm_mul(const ExtendedFloat &lhs, const ExtendedFloat &rhs)
ExtendedFloat & operator*=(const ExtendedFloat &rhs)
static ExtendedFloat denorm_sub(const ExtendedFloat &lhs, const ExtendedFloat &rhs)
static constexpr FloatType smallest_normalized_value
Definition: ExtendedFloat.h:73
bool operator>=(const double &rhs) const
static constexpr FloatType normalize_small_factor
Definition: ExtendedFloat.h:78
bool operator>=(const ExtendedFloat &rhs) const
ExtendedFloat & operator+=(const ExtendedFloat &rhs)
ExtendedFloat operator/(const ExtendedFloat &rhs) const
bool operator>(const ExtendedFloat &rhs) const
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
FloatType & float_part() noexcept
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
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