dconv 2.0
C++14 library for printing and parsing floating point numbers
Loading...
Searching...
No Matches
eisellemire.hpp
Go to the documentation of this file.
1
25#ifndef __DCONV_EISELLEMIRE_HPP__
26#define __DCONV_EISELLEMIRE_HPP__
27
28// dconv.
30#include <dconv/probe.hpp>
31
32// C++.
33#include <limits>
34
35// C.
36#include <cstring>
37#include <cstdint>
38
39namespace dconv
40{
41 namespace eisellemire
42 {
49 inline double compute (uint64_t significand, int64_t exponent) noexcept
50 {
51 static constexpr double pow10[] = {1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11,
52 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22};
53
54 double value = static_cast<double> (significand);
55
56 if (DCONV_LIKELY ((exponent >= -22) && (exponent <= 22) && (value <= 9007199254740991.0)))
57 {
58 return (exponent < 0) ? (value / pow10[-exponent]) : (value * pow10[exponent]);
59 }
60
61 if (DCONV_UNLIKELY ((exponent > 22) && (exponent < (22 + 16))))
62 {
63 const double scaled = value * pow10[exponent - 22];
64 if (scaled <= 9007199254740991.0)
65 {
66 return scaled * pow10[22];
67 }
68 }
69
70 if (DCONV_UNLIKELY (significand == 0 || exponent < -342))
71 {
72 return 0.0;
73 }
74
75 if (DCONV_UNLIKELY (exponent > 308))
76 {
77 return std::numeric_limits<double>::infinity ();
78 }
79
80 const int lz = __builtin_clzll (significand);
81 significand <<= lz;
82
83 const details::Power& power = details::eisellemirepow[exponent + 342];
84 uint64_t high, low;
85 details::umul128 (power.hi, significand, high, low);
86 if ((high & 0x1FF) == 0x1FF)
87 {
88 uint64_t secondHigh, secondLow;
89 details::umul128 (power.lo, significand, secondHigh, secondLow);
90 low += secondHigh;
91 high += (secondHigh > low);
92 }
93
94 const int upperbit = static_cast<int> (high >> 63);
95 const int shift = upperbit + 9;
96 uint64_t mantissa = high >> shift;
97 int64_t power2 = (((152170 + 65536) * exponent) >> 16) + 63 + upperbit - lz + 1023;
98
99 if (DCONV_UNLIKELY (power2 <= 0))
100 {
101 if (-power2 + 1 >= 64)
102 {
103 return 0.0;
104 }
105 mantissa >>= -power2 + 1;
106 mantissa += (mantissa & 1);
107 mantissa >>= 1;
108 power2 = (mantissa < (uint64_t (1) << 52)) ? 0 : 1;
109 }
110 else
111 {
112 if ((low <= 1) && (exponent >= -4) && (exponent <= 23) && ((mantissa & 3) == 1) &&
113 ((mantissa << shift) == high))
114 {
115 mantissa &= ~uint64_t (1);
116 }
117
118 mantissa += (mantissa & 1);
119 mantissa >>= 1;
120
121 if (DCONV_UNLIKELY (mantissa >= (uint64_t (2) << 52)))
122 {
123 mantissa = uint64_t (1) << 52;
124 ++power2;
125 }
126
127 if (DCONV_UNLIKELY (power2 >= 0x7FF))
128 {
129 return std::numeric_limits<double>::infinity ();
130 }
131 }
132
133 const uint64_t bits = (static_cast<uint64_t> (power2) << 52) | (mantissa & ((uint64_t (1) << 52) - 1));
134 memcpy (&value, &bits, sizeof (double));
135 return value;
136 }
137 }
138}
139
140#endif
constexpr Power eisellemirepow[]
Definition eisellemirepow.hpp:35
void umul128(uint64_t a, uint64_t b, uint64_t &high, uint64_t &low) noexcept
multiply two 64 bits unsigned integers.
Definition power.hpp:52
double compute(uint64_t significand, int64_t exponent) noexcept
convert double using fast path.
Definition eisellemire.hpp:49
Definition atod.hpp:47
#define DCONV_LIKELY(x)
Definition probe.hpp:37
#define DCONV_UNLIKELY(x)
Definition probe.hpp:38
128 bits power.
Definition power.hpp:37
uint64_t hi
high 64 bits.
Definition power.hpp:39
uint64_t lo
low 64 bits.
Definition power.hpp:42