sparrow 1.4.0
C++20 idiomatic APIs for the Apache Arrow Columnar Format
Loading...
Searching...
No Matches
int256_t.hpp
Go to the documentation of this file.
1
2// SPARROW: THIS HAS BEEN COPY-PASTED FROM https://github.com/kimwalisch/primesum/blob/master/include/int256_t.hpp
3// PLEASE UPDATE THIS COMMENT IF YOU REPLACE THIS
4// SEE README.md for rational
6// Modification from the original:
7// - disabled next_larger_type
8// - disabled OpenMP support
9// - disabled io operators (abigiousty...)
10// - update operator<<
22
23#ifndef INT256_T_HPP
24#define INT256_T_HPP
25
26#include <cassert>
27#include <cstdint>
28#include <cstddef>
29#include <cstdlib>
30#include <string>
31#include <ostream>
32#include <limits>
33#include <type_traits>
34#include <utility>
35
36#include "int128_t.hpp"
37
38namespace primesum {
39
41{
42public:
44 : low(0)
45 , high(0)
46 {
47 }
48
49 template <typename T,
50 typename = typename std::enable_if<prt::is_integral<T>::value>::type>
52 : low(x),
53 high((x < 0) ? -1 : 0)
54 {
55 }
56
57 bool operator==(const int256_t& other) const
58 {
59 return low == other.low &&
60 high == other.high;
61 }
62
63 bool operator!=(const int256_t& other) const
64 {
65 return !(*this == other);
66 }
67
68 bool operator<(const int256_t& other) const
69 {
70 int128_t hi1 = high;
71 int128_t hi2 = other.high;
72
73 return hi1 < hi2 || (hi1 == hi2 && low < other.low);
74 }
75
76 bool operator<=(const int256_t& other) const
77 {
78 return !(other < *this);
79 }
80
81 bool operator>(const int256_t& other) const
82 {
83 return other < *this;
84 }
85
86 bool operator>=(const int256_t& other) const
87 {
88 return !(*this < other);
89 }
90
92 {
93 return *this;
94 }
95
97 {
98 int256_t res = ~*this;
99 ++res;
100 return res;
101 }
102
104 {
105 return int256_t(~low, ~high);
106 }
107
109 {
110 if (low == 0)
111 high--;
112
113 low--;
114 return *this;
115 }
116
118 {
119 low++;
120 if (low == 0)
121 high++;
122
123 return *this;
124 }
125
127 {
128 int256_t res = *this;
129 --*this;
130 return res;
131 }
132
134 {
135 int256_t res = *this;
136 ++*this;
137 return res;
138 }
139
140 int256_t operator+(const int256_t& other) const
141 {
142 int256_t res;
143
144 res.high = high + other.high;
145 res.low = low + other.low;
146
147 if (res.low < other.low)
148 res.high++;
149
150 return res;
151 }
152
153 int256_t operator-(const int256_t& other) const
154 {
155 int256_t res;
156
157 res.high = high - other.high;
158 res.low = low - other.low;
159
160 if (res.low > low)
161 res.high--;
162
163 return res;
164 }
165
166 int256_t operator*(const int256_t& other) const
167 {
169
170 if (low <= max64 &&
171 other.low <= max64 &&
172 ((high == 0 || ~high == 0) &&
173 (other.high == 0 || ~other.high == 0)))
174 {
175 return int256_t(low * other.low,
176 (high == other.high) ? 0 : -1);
177 }
178 else
179 {
180 auto al = low & max64;
181 auto ah = low >> 64;
182 auto bl = other.low & max64;
183 auto bh = other.low >> 64;
184
185 auto x = al * bl;
186 auto y = al * bh;
187 auto z = ah * bl;
188 auto w = ah * bh;
189
190 return int256_t(y << 64, y >> 64) +
191 int256_t(z << 64, z >> 64) +
192 int256_t(x, w + low * other.high + high * other.low);
193 }
194 }
195
196 int256_t operator/(const int256_t& other) const
197 {
198 return div256(other).first;
199 }
200
201 int256_t operator%(const int256_t& other) const
202 {
203 return div256(other).second;
204 }
205
206 int256_t operator&(const int256_t& other) const
207 {
208 return int256_t(low & other.low,
209 high & other.high);
210 }
211
212 int256_t operator|(const int256_t& other) const
213 {
214 return int256_t(low | other.low,
215 high | other.high);
216 }
217
218 int256_t operator^(const int256_t& other) const
219 {
220 return int256_t(low ^ other.low,
221 high ^ other.high);
222 }
223
224 int256_t operator<<(std::size_t bits) const
225 {
226 if (bits >= 128)
227 return int256_t(0, low << (bits - 128));
228 else
229 return int256_t(low << bits, (high << bits) | (low >> (128 - bits)));
230 }
231
232 int256_t operator>>(std::size_t bits) const
233 {
234 if (bits >= 128)
235 return int256_t(high >> (bits - 128), 0);
236 else
237 return int256_t((low >> bits) | (high << (128 - bits)), high >> bits);
238 }
239
241 {
242 *this = *this + other;
243 return *this;
244 }
245
247 {
248 *this = *this - other;
249 return *this;
250 }
251
253 {
254 *this = *this * other;
255 return *this;
256 }
257
259 {
260 *this = *this / other;
261 return *this;
262 }
263
265 {
266 *this = *this % other;
267 return *this;
268 }
269
271 {
272 *this = *this & other;
273 return *this;
274 }
275
277 {
278 *this = *this | other;
279 return *this;
280 }
281
283 {
284 *this = *this ^ other;
285 return *this;
286 }
287
288 int256_t& operator<<=(std::size_t bits)
289 {
290 *this = *this << bits;
291 return *this;
292 }
293
294 int256_t& operator>>=(std::size_t bits)
295 {
296 *this = *this >> bits;
297 return *this;
298 }
299
300 template <typename T,
301 typename = typename std::enable_if<prt::is_integral<T>::value>::type>
302 bool operator==(T x) const
303 {
304 return *this == int256_t(x);
305 }
306
307 template <typename T,
308 typename = typename std::enable_if<prt::is_integral<T>::value>::type>
309 bool operator!=(T x) const
310 {
311 return *this != int256_t(x);
312 }
313
314 template <typename T,
315 typename = typename std::enable_if<prt::is_integral<T>::value>::type>
316 bool operator<(T x) const
317 {
318 return *this < int256_t(x);
319 }
320
321 template <typename T,
322 typename = typename std::enable_if<prt::is_integral<T>::value>::type>
323 bool operator<=(T x) const
324 {
325 return *this <= int256_t(x);
326 }
327
328 template <typename T,
329 typename = typename std::enable_if<prt::is_integral<T>::value>::type>
330 bool operator>(T x) const
331 {
332 return *this > int256_t(x);
333 }
334
335 template <typename T,
336 typename = typename std::enable_if<prt::is_integral<T>::value>::type>
337 bool operator>=(T x) const
338 {
339 return *this >= int256_t(x);
340 }
341
342 template <typename T,
343 typename = typename std::enable_if<prt::is_integral<T>::value>::type>
345 {
346 return *this + int256_t(x);
347 }
348
349 template <typename T,
350 typename = typename std::enable_if<prt::is_integral<T>::value>::type>
352 {
353 return *this - int256_t(x);
354 }
355
356 template <typename T,
357 typename = typename std::enable_if<prt::is_integral<T>::value>::type>
359 {
360 return *this * int256_t(x);
361 }
362
363 template <typename T,
364 typename = typename std::enable_if<prt::is_integral<T>::value>::type>
366 {
367 return *this / int256_t(x);
368 }
369
370 template <typename T,
371 typename = typename std::enable_if<prt::is_integral<T>::value>::type>
373 {
374 return *this % int256_t(x);
375 }
376
377 template <typename T,
378 typename = typename std::enable_if<prt::is_integral<T>::value>::type>
380 {
381 return *this & int256_t(x);
382 }
383
384 template <typename T,
385 typename = typename std::enable_if<prt::is_integral<T>::value>::type>
387 {
388 return *this | int256_t(x);
389 }
390
391 template <typename T,
392 typename = typename std::enable_if<prt::is_integral<T>::value>::type>
394 {
395 return *this ^ int256_t(x);
396 }
397
398 template <typename T,
399 typename = typename std::enable_if<prt::is_integral<T>::value>::type>
401 {
402 return *this << static_cast<std::size_t>(x);
403 }
404
405 template <typename T,
406 typename = typename std::enable_if<prt::is_integral<T>::value>::type>
408 {
409 return *this >> static_cast<std::size_t>(x);
410 }
411
412 explicit operator std::int8_t() const
413 {
414 return (*this < 0)
415 ? static_cast<std::int8_t>(-(static_cast<int64_t>((low - 1) ^ prt::numeric_limits<uint128_t>::max())))
416 : static_cast<std::int8_t>(low);
417 }
418
419 explicit operator std::int16_t() const
420 {
421 return (*this < 0)
422 ? static_cast<std::int16_t>(-(static_cast<int64_t>((low - 1) ^ prt::numeric_limits<uint128_t>::max())))
423 : static_cast<std::int16_t>(low);
424 }
425
426 explicit operator std::int32_t() const
427 {
428 return (*this < 0)
429 ? -static_cast<std::int32_t>(
431 : static_cast<std::int32_t>(low);
432 }
433
434 explicit operator std::int64_t() const
435 {
436 return (*this < 0)
437 ? -static_cast<std::int64_t>(
439 : static_cast<std::int64_t>(low);
440 }
441
442 explicit operator int128_t() const
443 {
444 return (*this < 0)
445 ? -static_cast<int128_t>(
447 : static_cast<int128_t>(low);
448 }
449
450 explicit operator std::uint8_t() const
451 {
452 return static_cast<std::uint8_t>(low);
453 }
454
455 explicit operator std::uint16_t() const
456 {
457 return static_cast<std::uint16_t>(low);
458 }
459
460 explicit operator std::uint32_t() const
461 {
462 return static_cast<std::uint32_t>(low);
463 }
464
465 explicit operator std::uint64_t() const
466 {
467 return static_cast<std::uint64_t>(low);
468 }
469
470 explicit operator uint128_t() const
471 {
472 return static_cast<uint128_t>(low);
473 }
474
475 friend std::ostream& operator<<(std::ostream& out, int256_t n);
476
477private:
478 uint128_t low;
479 uint128_t high;
480
481 int256_t(uint128_t low, uint128_t high)
482 : low(low)
483 , high(high)
484 {
485 }
486
487 static int256_t min_value()
488 {
489 return int256_t(0, static_cast<uint128_t>(prt::numeric_limits<int128_t>::min()));
490 }
491
492 static int256_t max_value()
493 {
496 }
497
498 bool get_bit(std::size_t bit) const
499 {
500 if (bit >= 128)
501 return (high >> (bit - 128)) & 1;
502 else
503 return (low >> bit) & 1;
504 }
505
506 void set_bit(std::size_t bit, bool value)
507 {
508 if (bit >= 256)
509 return;
510
511 if (bit >= 128)
512 {
513 uint128_t mask = static_cast<uint128_t>(1) << (bit - 128);
514
515 if (value)
516 high |= mask;
517 else
518 high &= ~mask;
519 }
520 else
521 {
522 uint128_t mask = static_cast<uint128_t>(1) << bit;
523
524 if (value)
525 low |= mask;
526 else
527 low &= ~mask;
528 }
529 }
530
531 int find_most_significant_bit() const
532 {
533 auto x = *this;
534 int pos = 0;
535
536 while (x != 0)
537 {
538 pos++;
539 x >>= 1;
540 }
541
542 return pos;
543 }
544
546 std::pair<int256_t, int256_t> udiv256(const int256_t& other) const
547 {
548 int256_t zero = 0;
549 int256_t one = 1;
550
551 if (other == 0)
552 {
553 assert(other != 0);
554 std::abort();
555 return { zero, zero };
556 }
557 else if (other == 1)
558 {
559 return { *this, zero };
560 }
561 else if (*this == other)
562 {
563 return { one, zero };
564 }
565 else if (*this == 0 || (*this != min_value() && *this < other))
566 {
567 return { zero, *this };
568 }
569 else if (high == 0 && other.high == 0)
570 {
571 return { int256_t(low / other.low, 0),
572 int256_t(low % other.low, 0) };
573 }
574 else
575 {
576 int256_t quotient = 0;
578
579 for (int i = find_most_significant_bit(); i >= 0 && i <= 256; i--)
580 {
581 remainder <<= 1;
582 remainder.set_bit(static_cast<std::size_t>(0), get_bit(static_cast<std::size_t>(i)));
583
584 if (remainder >= other)
585 {
586 remainder -= other;
587 quotient.set_bit(static_cast<std::size_t>(i), true);
588 }
589 }
590 return { quotient, remainder };
591 }
592 }
593
595 std::pair<int256_t, int256_t> div256(const int256_t& other) const
596 {
597 if (*this < 0)
598 {
599 auto x = -*this;
600
601 if (other < 0)
602 {
603 auto res = x.udiv256(-other);
604 return { res.first, -res.second };
605 }
606 else
607 {
608 auto res = x.udiv256(other);
609 return { -res.first, -res.second };
610 }
611 }
612 else
613 {
614 if (other < 0)
615 {
616 auto res = udiv256(-other);
617 return { -res.first, res.second };
618 }
619 else
620 return udiv256(other);
621 }
622 }
623};
624
625inline std::ostream& operator<<(std::ostream& stream, int256_t n)
626{
627 std::string str;
628
629 if (n < 0)
630 {
631 stream << "-";
632 n = -n;
633 }
634
635 while (n > 0)
636 {
637# if defined(__GNUC__)
638# pragma GCC diagnostic push
639# pragma GCC diagnostic ignored "-Wconversion"
640# endif
641 str += '0' + std::int8_t(n % 10);
642# if defined(__GNUC__)
643# pragma GCC diagnostic pop
644# endif
645 n /= 10;
646 }
647
648 if (str.empty())
649 str = "0";
650
651 stream << std::string(str.rbegin(), str.rend());
652
653 return stream;
654}
655
656inline std::string to_string(const int256_t& n)
657{
658 std::ostringstream oss;
659 oss << n;
660 return oss.str();
661
662}
663
664
665// template <typename T>
666// struct next_larger_type
667// {
668// typedef typename std::conditional<std::is_same<T, int64_t>::value, int128_t,
669// typename std::conditional<std::is_same<T, uint64_t>::value, uint128_t,
670// typename std::conditional<std::is_same<T, int128_t>::value, int256_t,
671// typename std::conditional<std::is_same<T, uint128_t>::value, int256_t,
672// T>::type>::type>::type>::type type;
673// };
674
675} // namespace
676
677// #ifdef _OPENMP
678
679// namespace primesum {
680
681// /// Requires OpenMP >= 4.0
682// #pragma omp declare reduction(+ : int256_t : omp_out += omp_in)
683
684// } // namespace
685
686// #endif
687
688#endif
operator std::int64_t() const
Definition int256_t.hpp:434
int256_t & operator&=(const int256_t &other)
Definition int256_t.hpp:270
int256_t operator>>(std::size_t bits) const
Definition int256_t.hpp:232
int256_t operator+() const
Definition int256_t.hpp:91
int256_t & operator|=(const int256_t &other)
Definition int256_t.hpp:276
int256_t & operator^=(const int256_t &other)
Definition int256_t.hpp:282
bool operator>=(const int256_t &other) const
Definition int256_t.hpp:86
int256_t operator<<(std::size_t bits) const
Definition int256_t.hpp:224
int256_t & operator--()
Definition int256_t.hpp:108
bool operator>=(T x) const
Definition int256_t.hpp:337
bool operator!=(const int256_t &other) const
Definition int256_t.hpp:63
int256_t & operator-=(const int256_t &other)
Definition int256_t.hpp:246
int256_t operator--(int)
Definition int256_t.hpp:126
int256_t & operator<<=(std::size_t bits)
Definition int256_t.hpp:288
int256_t operator%(const int256_t &other) const
Definition int256_t.hpp:201
int256_t operator/(const int256_t &other) const
Definition int256_t.hpp:196
int256_t & operator%=(const int256_t &other)
Definition int256_t.hpp:264
bool operator>(const int256_t &other) const
Definition int256_t.hpp:81
bool operator>(T x) const
Definition int256_t.hpp:330
int256_t operator++(int)
Definition int256_t.hpp:133
int256_t & operator/=(const int256_t &other)
Definition int256_t.hpp:258
int256_t & operator+=(const int256_t &other)
Definition int256_t.hpp:240
bool operator<(const int256_t &other) const
Definition int256_t.hpp:68
int256_t operator+(const int256_t &other) const
Definition int256_t.hpp:140
int256_t operator^(const int256_t &other) const
Definition int256_t.hpp:218
int256_t operator-() const
Definition int256_t.hpp:96
bool operator==(const int256_t &other) const
Definition int256_t.hpp:57
int256_t operator*(const int256_t &other) const
Definition int256_t.hpp:166
bool operator<=(T x) const
Definition int256_t.hpp:323
int256_t operator|(const int256_t &other) const
Definition int256_t.hpp:212
int256_t operator~() const
Definition int256_t.hpp:103
bool operator<=(const int256_t &other) const
Definition int256_t.hpp:76
bool operator==(T x) const
Definition int256_t.hpp:302
int256_t & operator++()
Definition int256_t.hpp:117
int256_t & operator>>=(std::size_t bits)
Definition int256_t.hpp:294
int256_t & operator*=(const int256_t &other)
Definition int256_t.hpp:252
int256_t operator-(const int256_t &other) const
Definition int256_t.hpp:153
bool operator<(T x) const
Definition int256_t.hpp:316
bool operator!=(T x) const
Definition int256_t.hpp:309
int256_t operator&(const int256_t &other) const
Definition int256_t.hpp:206
Support for int128_t, uint128_t types.
half remainder(half x, half y)
Remainder of division.
std::string to_string(const uint128_t &n)
Definition int128_t.hpp:79
std::ostream & operator<<(std::ostream &stream, int256_t n)
Definition int256_t.hpp:625
static constexpr int128_t min()
Definition int128_t.hpp:111
static constexpr T max()
Definition int128_t.hpp:102