Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
uint128.cpp
Go to the documentation of this file.
1#include <fc/uint128.hpp>
2#include <fc/variant.hpp>
4#include <boost/multiprecision/cpp_int.hpp>
5
6#include <stdexcept>
7#include "byteswap.hpp"
8
9namespace fc
10{
11 typedef boost::multiprecision::uint128_t m128;
12
13 template <typename T>
14 static void divide(const T &numerator, const T &denominator, T &quotient, T &remainder)
15 {
16 static const int bits = sizeof(T) * 8;//CHAR_BIT;
17
18 if(denominator == 0) {
19 throw std::domain_error("divide by zero");
20 } else {
21 T n = numerator;
22 T d = denominator;
23 T x = 1;
24 T answer = 0;
25
26
27 while((n >= d) && (((d >> (bits - 1)) & 1) == 0)) {
28 x <<= 1;
29 d <<= 1;
30 }
31
32 while(x != 0) {
33 if(n >= d) {
34 n -= d;
35 answer |= x;
36 }
37
38 x >>= 1;
39 d >>= 1;
40 }
41
42 quotient = answer;
43 remainder = n;
44 }
45 }
46
47 uint128::uint128(const std::string &sz)
48 :hi(0), lo(0)
49 {
50 // do we have at least one character?
51 if(!sz.empty()) {
52 // make some reasonable assumptions
53 int radix = 10;
54 bool minus = false;
55
56 std::string::const_iterator i = sz.begin();
57
58 // check for minus sign, i suppose technically this should only apply
59 // to base 10, but who says that -0x1 should be invalid?
60 if(*i == '-') {
61 ++i;
62 minus = true;
63 }
64
65 // check if there is radix changing prefix (0 or 0x)
66 if(i != sz.end()) {
67 if(*i == '0') {
68 radix = 8;
69 ++i;
70 if(i != sz.end()) {
71 if(*i == 'x') {
72 radix = 16;
73 ++i;
74 }
75 }
76 }
77
78 while(i != sz.end()) {
79 unsigned int n = 0;
80 const char ch = *i;
81
82 if(ch >= 'A' && ch <= 'Z') {
83 if(((ch - 'A') + 10) < radix) {
84 n = (ch - 'A') + 10;
85 } else {
86 break;
87 }
88 } else if(ch >= 'a' && ch <= 'z') {
89 if(((ch - 'a') + 10) < radix) {
90 n = (ch - 'a') + 10;
91 } else {
92 break;
93 }
94 } else if(ch >= '0' && ch <= '9') {
95 if((ch - '0') < radix) {
96 n = (ch - '0');
97 } else {
98 break;
99 }
100 } else {
101 /* completely invalid character */
102 break;
103 }
104
105 (*this) *= radix;
106 (*this) += n;
107
108 ++i;
109 }
110 }
111
112 // if this was a negative number, do that two's compliment madness :-P
113 if(minus) {
114 *this = -*this;
115 }
116 }
117 }
118
119
120 uint128::operator bigint()const
121 {
122 auto tmp = uint128( bswap_64( hi ), bswap_64( lo ) );
123 bigint bi( (char*)&tmp, sizeof(tmp) );
124 return bi;
125 }
126 uint128::uint128( const fc::bigint& bi )
127 {
128 *this = uint128( std::string(bi) ); // TODO: optimize this...
129 }
130
131 uint128::operator std::string ()const
132 {
133 if(*this == 0) { return "0"; }
134
135 // at worst it will be size digits (base 2) so make our buffer
136 // that plus room for null terminator
137 static char sz [128 + 1];
138 sz[sizeof(sz) - 1] = '\0';
139
140 uint128 ii(*this);
141 int i = 128 - 1;
142
143 while (ii != 0 && i) {
144
145 uint128 remainder;
146 divide(ii, uint128(10), ii, remainder);
147 sz [--i] = "0123456789abcdefghijklmnopqrstuvwxyz"[remainder.to_integer()];
148 }
149
150 return &sz[i];
151 }
152
153
154 uint128& uint128::operator<<=(const uint128& rhs)
155 {
156 if(rhs >= 128)
157 {
158 hi = 0;
159 lo = 0;
160 }
161 else
162 {
163 unsigned int n = rhs.to_integer();
164 const unsigned int halfsize = 128 / 2;
165
166 if(n >= halfsize){
167 n -= halfsize;
168 hi = lo;
169 lo = 0;
170 }
171
172 if(n != 0) {
173 // shift high half
174 hi <<= n;
175
176 const uint64_t mask(~(uint64_t(-1) >> n));
177
178 // and add them to high half
179 hi |= (lo & mask) >> (halfsize - n);
180
181 // and finally shift also low half
182 lo <<= n;
183 }
184 }
185
186 return *this;
187 }
188
189 uint128 & uint128::operator>>=(const uint128& rhs)
190 {
191 if(rhs >= 128)
192 {
193 hi = 0;
194 lo = 0;
195 }
196 else
197 {
198 unsigned int n = rhs.to_integer();
199 const unsigned int halfsize = 128 / 2;
200
201 if(n >= halfsize) {
202 n -= halfsize;
203 lo = hi;
204 hi = 0;
205 }
206
207 if(n != 0) {
208 // shift low half
209 lo >>= n;
210
211 // get lower N bits of high half
212 const uint64_t mask(~(uint64_t(-1) << n));
213
214 // and add them to low qword
215 lo |= (hi & mask) << (halfsize - n);
216
217 // and finally shift also high half
218 hi >>= n;
219 }
220 }
221 return *this;
222 }
223
224 uint128& uint128::operator/=(const uint128 &b)
225 {
226 auto self = (m128(hi) << 64) + m128(lo);
227 auto other = (m128(b.hi) << 64) + m128(b.lo);
228 self /= other;
229 hi = static_cast<uint64_t>(self >> 64);
230 lo = static_cast<uint64_t>((self << 64 ) >> 64);
231
232 /*
233 uint128 remainder;
234 divide(*this, b, *this, remainder ); //, *this);
235 if( tmp.hi != hi || tmp.lo != lo ) {
236 std::cerr << tmp.hi << " " << hi <<"\n";
237 std::cerr << tmp.lo << " " << lo << "\n";
238 exit(1);
239 }
240 */
241
242 /*
243 const auto& b128 = std::reinterpret_cast<const m128&>(b);
244 auto& this128 = std::reinterpret_cast<m128&>(*this);
245 this128 /= b128;
246 */
247 return *this;
248 }
249
250 uint128& uint128::operator%=(const uint128 &b)
251 {
252 uint128 quotient;
253 divide(*this, b, quotient, *this);
254 return *this;
255 }
256
257 uint128& uint128::operator*=(const uint128 &b)
258 {
259 uint64_t a0 = (uint32_t) (this->lo );
260 uint64_t a1 = (uint32_t) (this->lo >> 0x20);
261 uint64_t a2 = (uint32_t) (this->hi );
262 uint64_t a3 = (uint32_t) (this->hi >> 0x20);
263
264 uint64_t b0 = (uint32_t) (b.lo );
265 uint64_t b1 = (uint32_t) (b.lo >> 0x20);
266 uint64_t b2 = (uint32_t) (b.hi );
267 uint64_t b3 = (uint32_t) (b.hi >> 0x20);
268
269 // (a0 + (a1 << 0x20) + (a2 << 0x40) + (a3 << 0x60)) *
270 // (b0 + (b1 << 0x20) + (b2 << 0x40) + (b3 << 0x60)) =
271 // a0 * b0
272 //
273 // (a1 * b0 + a0 * b1) << 0x20
274 // (a2 * b0 + a1 * b1 + a0 * b2) << 0x40
275 // (a3 * b0 + a2 * b1 + a1 * b2 + a0 * b3) << 0x60
276 //
277 // all other cross terms are << 0x80 or higher, thus do not appear in result
278
279 this->hi = 0;
280 this->lo = a3*b0;
281 (*this) += a2*b1;
282 (*this) += a1*b2;
283 (*this) += a0*b3;
284 (*this) <<= 0x20;
285 (*this) += a2*b0;
286 (*this) += a1*b1;
287 (*this) += a0*b2;
288 (*this) <<= 0x20;
289 (*this) += a1*b0;
290 (*this) += a0*b1;
291 (*this) <<= 0x20;
292 (*this) += a0*b0;
293
294 return *this;
295 }
296
297 void uint128::full_product( const uint128& a, const uint128& b, uint128& result_hi, uint128& result_lo )
298 {
299 // (ah * 2**64 + al) * (bh * 2**64 + bl)
300 // = (ah * bh * 2**128 + al * bh * 2**64 + ah * bl * 2**64 + al * bl
301 // = P * 2**128 + (Q + R) * 2**64 + S
302 // = Ph * 2**192 + Pl * 2**128
303 // + Qh * 2**128 + Ql * 2**64
304 // + Rh * 2**128 + Rl * 2**64
305 // + Sh * 2**64 + Sl
306 //
307
308 uint64_t ah = a.hi;
309 uint64_t al = a.lo;
310 uint64_t bh = b.hi;
311 uint64_t bl = b.lo;
312
313 uint128 s = al;
314 s *= bl;
315 uint128 r = ah;
316 r *= bl;
317 uint128 q = al;
318 q *= bh;
319 uint128 p = ah;
320 p *= bh;
321
322 uint64_t sl = s.lo;
323 uint64_t sh = s.hi;
324 uint64_t rl = r.lo;
325 uint64_t rh = r.hi;
326 uint64_t ql = q.lo;
327 uint64_t qh = q.hi;
328 uint64_t pl = p.lo;
329 uint64_t ph = p.hi;
330
331 uint64_t y[4]; // final result
332 y[0] = sl;
333
334 uint128 acc = sh;
335 acc += ql;
336 acc += rl;
337 y[1] = acc.lo;
338 acc = acc.hi;
339 acc += qh;
340 acc += rh;
341 acc += pl;
342 y[2] = acc.lo;
343 y[3] = acc.hi + ph;
344
345 result_hi = uint128( y[3], y[2] );
346 result_lo = uint128( y[1], y[0] );
347
348 return;
349 }
350
351 static uint8_t _popcount_64( uint64_t x )
352 {
353 static const uint64_t m[] = {
354 0x5555555555555555ULL,
355 0x3333333333333333ULL,
356 0x0F0F0F0F0F0F0F0FULL,
357 0x00FF00FF00FF00FFULL,
358 0x0000FFFF0000FFFFULL,
359 0x00000000FFFFFFFFULL
360 };
361 // TODO future optimization: replace slow, portable version
362 // with fast, non-portable __builtin_popcountll intrinsic
363 // (when available)
364
365 for( int i=0, w=1; i<6; i++, w+=w )
366 {
367 x = (x & m[i]) + ((x >> w) & m[i]);
368 }
369 return uint8_t(x);
370 }
371
372 uint8_t uint128::popcount()const
373 {
374 return _popcount_64( lo ) + _popcount_64( hi );
375 }
376
377 void to_variant( const uint128& var, variant& vo ) { vo = std::string(var); }
378 void from_variant( const variant& var, uint128& vo ){ vo = uint128(var.as_string()); }
379/*
380 void to_variant( const unsigned __int128& var, variant& vo ) { to_variant( uint128(var), vo); }
381 void from_variant( const variant& var, unsigned __int128& vo ) {
382 uint128 tmp;
383 from_variant( var, tmp );
384 vo = (unsigned __int128)tmp;
385 }
386*/
387} // namespace fc
388
389
390/*
391 * Portions of the above code were adapted from the work of Evan Teran.
392 *
393 * Copyright (c) 2008
394 * Evan Teran
395 *
396 * Permission to use, copy, modify, and distribute this software and its
397 * documentation for any purpose and without fee is hereby granted, provided
398 * that the above copyright notice appears in all copies and that both the
399 * copyright notice and this permission notice appear in supporting
400 * documentation, and that the same name not be used in advertising or
401 * publicity pertaining to distribution of the software without specific,
402 * written prior permission. We make no representations about the
403 * suitability this software for any purpose. It is provided "as is"
404 * without express or implied warranty.
405 */
const mie::Vuint & p
Definition bn.cpp:27
const mie::Vuint & r
Definition bn.cpp:28
an implementation of 128 bit unsigned integer
Definition uint128.hpp:22
uint32_t to_integer() const
Definition uint128.hpp:95
uint64_t lo
Definition uint128.hpp:122
uint64_t hi
Definition uint128.hpp:121
stores null, int64, uint64, double, bool, string, std::vector<variant>, and variant_object's.
Definition variant.hpp:191
string as_string() const
Definition variant.cpp:469
namespace sysio::chain
Definition authority.cpp:3
boost::multiprecision::uint128_t m128
Definition uint128.cpp:11
uint64_t y
Definition sha3.cpp:34
void from_variant(const fc::variant &v, sysio::chain::chain_id_type &cid)
void to_variant(const sysio::chain::shared_public_key &var, fc::variant &vo)
Definition authority.cpp:4
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition pointer.h:1181
#define T(meth, val, expected)
unsigned int uint32_t
Definition stdint.h:126
unsigned char uint8_t
Definition stdint.h:124
unsigned __int64 uint64_t
Definition stdint.h:136
CK_ULONG d
char * s