1 /* This file is part of Jellyfish.
2
3 Jellyfish is free software: you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation, either version 3 of the License, or
6 (at your option) any later version.
7
8 Jellyfish is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with Jellyfish. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 #ifndef _INT128_H_
18 #define _INT128_H_
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #ifndef HAVE_INT128
23 #error "The type __int128 is not supported"
24 #endif
25 #endif
26
27 #include <unistd.h>
28 #include <stdint.h>
29 #include <iostream>
30 #include <sstream>
31 #include <limits>
32 #include <cstring>
33
34 // Output of __int128: this might be slow
35 namespace __int128_ns {
36 template<int base>
__print_digits(std::ostream & os,unsigned __int128 x,bool lower=true)37 void __print_digits(std::ostream& os, unsigned __int128 x,
38 bool lower = true) {
39 char buf[50];
40 char* ptr = buf + sizeof(buf);
41 do {
42 int o = x % base;
43 if(o < 10) {
44 *--ptr = '0' + o;
45 } else {
46 *--ptr = (lower ? 'a' : 'A') + o - 10;
47 }
48 x /= base;
49 } while (x > 0);
50 os.write(ptr, buf + sizeof(buf) - ptr);
51 }
52
is_negative(unsigned __int128 x)53 inline bool is_negative(unsigned __int128 x) { return false; }
is_negative(__int128 x)54 inline bool is_negative(__int128 x) { return x < 0; }
55
56 template<typename T>
__print_decimal(std::ostream & prefix,std::ostream & os,T x,const std::ios::fmtflags & ff)57 void __print_decimal(std::ostream& prefix, std::ostream& os, T x,
58 const std::ios::fmtflags& ff) {
59 if((ff & std::ios::showpos) && x > 0)
60 prefix << "+";
61 if(x == 0) {
62 os << "0";
63 return;
64 }
65 if(is_negative(x)) {
66 prefix << "-";
67 x = -x;
68 }
69 __print_digits<10>(os, x);
70 }
71
72 void __print_bases(std::ostream& prefix, std::ostream& os,
73 unsigned __int128 x,
74 const std::ios::fmtflags& ff);
75
76 template<typename T>
__print_buf(std::ostream & prefix,std::ostream & os,T x,const std::ios::fmtflags & ff)77 void __print_buf(std::ostream& prefix, std::ostream& os, T x,
78 const std::ios::fmtflags& ff) {
79 if(ff & std::ios::dec)
80 __print_decimal(prefix, os, x, ff);
81 else
82 __print_bases(prefix, os, (unsigned __int128)x, ff);
83 }
84
85 template<typename T>
__print(std::ostream & os,T x)86 void __print(std::ostream&os, T x) {
87 const std::ios_base::fmtflags ff = os.flags();
88
89 if(!(ff & std::ios::adjustfield))
90 return __print_buf(os, os, x, ff);
91
92 std::ostringstream prefix;
93 std::ostringstream buf;
94 __print_buf(prefix, buf, x, ff);
95 ssize_t nb_padding = os.width() - (prefix.str().size() + buf.str().size());
96 if(nb_padding <= 0) {
97 os.write(prefix.str().c_str(), prefix.tellp());
98 os.write(buf.str().c_str(), buf.tellp());
99 return;
100 }
101
102 char padding[nb_padding];
103 memset(padding, os.fill(), nb_padding);
104 if(ff & std::ios::right)
105 os.write(padding, nb_padding);
106 os.write(prefix.str().c_str(), prefix.tellp());
107 if(ff & std::ios::internal)
108 os.write(padding, nb_padding);
109 os.write(buf.str().c_str(), buf.tellp());
110 if(ff & std::ios::left)
111 os.write(padding, nb_padding);
112 }
113 }
114
115 inline
operator <<(std::ostream & os,__int128 x)116 std::ostream& operator<<(std::ostream& os, __int128 x) {
117 __int128_ns::__print(os, x);
118 return os;
119 }
120
121 inline
operator <<(std::ostream & os,unsigned __int128 x)122 std::ostream& operator<<(std::ostream& os, unsigned __int128 x) {
123 __int128_ns::__print(os, x);
124 return os;
125 }
126
127 #ifndef HAVE_NUMERIC_LIMITS128
128 namespace std {
129 template<>
130 class numeric_limits<__int128> {
131 public:
132 static const bool is_specialized = true;
max()133 static __int128 max() { return (unsigned __int128)-1 >> 1; }
min()134 static __int128 min() { return max() + 1; }
135 static const int digits = 127;
136 static const int digits10 = 38;
137 #define NLS64 numeric_limits<int64_t>
138 static const bool is_signed = NLS64::is_signed;
139 static const bool is_integer = NLS64::is_integer;
140 static const bool is_exact = NLS64::is_exact;
141 static const int radix = NLS64::radix;
epsilon()142 static __int128 epsilon() { return NLS64::epsilon(); }
round_error()143 static __int128 round_error() { return NLS64::round_error(); }
144 static const int min_exponent = NLS64::min_exponent;
145 static const int min_exponent10 = NLS64::min_exponent10;
146 static const int max_exponent = NLS64::max_exponent;
147 static const int max_exponent10 = NLS64::max_exponent10;
148 static const bool has_infinity = NLS64::has_infinity;
149 static const bool has_quiet_NaN = NLS64::has_quiet_NaN;
150 static const bool has_signaling_NaN = NLS64::has_signaling_NaN;
151 static const float_denorm_style has_denorm = NLS64::has_denorm;
152 static const bool has_denorm_loss = NLS64::has_denorm_loss;
infinity()153 static __int128 infinity() { return NLS64::infinity(); }
quiet_NaN()154 static __int128 quiet_NaN() { return NLS64::quiet_NaN(); }
signaling_NaN()155 static __int128 signaling_NaN() { return NLS64::signaling_NaN(); }
denorm_min()156 static __int128 denorm_min() { return NLS64::denorm_min(); }
157 static const bool is_iec559 = NLS64::is_iec559;
158 static const bool is_bounded = NLS64::is_bounded;
159 static const bool is_modulo = NLS64::is_modulo;
160 static const bool traps = NLS64::traps;
161 static const bool tinyness_before = NLS64::tinyness_before;
162 static const float_round_style round_style = NLS64::round_style;
163 };
164
165 template<>
166 class numeric_limits<unsigned __int128> {
167 public:
168 static const bool is_specialized = true;
max()169 static __int128 max() { return (unsigned __int128)-1; }
min()170 static __int128 min() { return 0; }
171 static const int digits = 128;
172 static const int digits10 = 39;
173 #define NLU64 numeric_limits<uint64_t>
174 static const bool is_signed = NLU64::is_signed;
175 static const bool is_integer = NLU64::is_integer;
176 static const bool is_exact = NLU64::is_exact;
177 static const int radix = NLU64::radix;
epsilon()178 static __int128 epsilon() { return NLU64::epsilon(); }
round_error()179 static __int128 round_error() { return NLU64::round_error(); }
180 static const int min_exponent = NLU64::min_exponent;
181 static const int min_exponent10 = NLU64::min_exponent10;
182 static const int max_exponent = NLU64::max_exponent;
183 static const int max_exponent10 = NLU64::max_exponent10;
184 static const bool has_infinity = NLU64::has_infinity;
185 static const bool has_quiet_NaN = NLU64::has_quiet_NaN;
186 static const bool has_signaling_NaN = NLU64::has_signaling_NaN;
187 static const float_denorm_style has_denorm = NLU64::has_denorm;
188 static const bool has_denorm_loss = NLU64::has_denorm_loss;
infinity()189 static __int128 infinity() { return NLU64::infinity(); }
quiet_NaN()190 static __int128 quiet_NaN() { return NLU64::quiet_NaN(); }
signaling_NaN()191 static __int128 signaling_NaN() { return NLU64::signaling_NaN(); }
denorm_min()192 static __int128 denorm_min() { return NLU64::denorm_min(); }
193 static const bool is_iec559 = NLU64::is_iec559;
194 static const bool is_bounded = NLU64::is_bounded;
195 static const bool is_modulo = NLU64::is_modulo;
196 static const bool traps = NLU64::traps;
197 static const bool tinyness_before = NLU64::tinyness_before;
198 static const float_round_style round_style = NLU64::round_style;
199 };
200 } // namespace std
201 #endif /* HAVE_NUMERIC_LIMITS128 */
202
203 #endif /* _INT128_H_ */
204