CeresEngine 0.2.0
A game development framework
Loading...
Searching...
No Matches
LargeInteger.hpp
Go to the documentation of this file.
1//
2// CeresEngine - A game development framework
3//
4// Created by Rogiel Sulzbach.
5// Copyright (c) 2018-2022 Rogiel Sulzbach. All rights reserved.
6//
7
8#pragma once
9
12
14
15#include <cmath>
16#include <cstdint>
17#include <limits>
18#include <type_traits>
19
20#if CE_COMPILER_MSVC
21#include <intrin.h>
22#endif
23#if __has_include(<bit>)
24#include <bit>
25#endif
26
27#if defined(__BYTE_ORDER__)
28#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
29#define CE_LARGE_INTEGER_LE
30#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
31#define CE_LARGE_INTEGER_BE
32#else
33#error Endianess not supported
34#endif
35#elif defined(WIN32)
36#define CE_LARGE_INTEGER_LE
37#else
38#error Endianess not supported
39#endif
40
41#if defined(__SIZEOF_INT128__) && __SIZEOF_INT128__ == 16 && defined(CRT_HAS_128BIT)
42#define CE_LARGE_INTEGER_HAS_INT128
43#endif
44
45namespace CeresEngine::inline Math {
46
54 static_assert(sizeof(Hi) == sizeof(Low), "Hi and Low type should have same size!");
55 static_assert(std::is_unsigned<Low>::value, "The Low part must be unsigned!");
56
57 template<typename, typename> friend struct LargeInteger;
58
62
63#if defined(CE_LARGE_INTEGER_LE)
64 Low low = 0; // NOLINT(misc-non-private-member-variables-in-classes)
65 Hi high = 0; // NOLINT(misc-non-private-member-variables-in-classes)
66#elif defined(CE_LARGE_INTEGER_BE)
67 Hi high = 0; // NOLINT(misc-non-private-member-variables-in-classes)
68 Low low = 0; // NOLINT(misc-non-private-member-variables-in-classes)
69#endif
70
71#if defined(CE_LARGE_INTEGER_LE)
72 constexpr LargeInteger(Hi high, Low low) : low(low), high(high) {}
73#elif defined(CE_LARGE_INTEGER_BE)
74 constexpr LargeInteger(Hi high, Low low)
75
76 : high(high), low(low) {}
77#endif
78
79 public:
81 constexpr LargeInteger() noexcept = default;
82
84 constexpr LargeInteger(const LargeInteger&) noexcept = default;
85
88 LargeInteger& operator=(const LargeInteger&) noexcept = default;
89
91 constexpr LargeInteger(LargeInteger&&) noexcept = default;
92
95 LargeInteger& operator=(LargeInteger&&) noexcept = default;
96
97 public:
102 template<typename THi> constexpr explicit LargeInteger(LargeInteger<THi, Low> value) noexcept : LargeInteger(Hi(value.high), value.low) {}
103
107 template<typename Tp,
108 typename = std::enable_if_t<std::is_integral_v<Tp>>>
109 constexpr LargeInteger(Tp value) noexcept // NOLINT explicit
110 : LargeInteger(
111 [](Tp value) constexpr {
112 if constexpr(sizeof(Hi) < sizeof(Tp)) {
113 return Hi(value >> (sizeof(Low) * 8));
114 } else {
115 return Hi(0);
116 }
117 }(value),
118 static_cast<Low>(value)) {}
119
124 template<typename Tp, typename = std::enable_if_t<std::is_integral_v<Tp>>> [[nodiscard]] constexpr explicit operator Tp() const noexcept {
125 if constexpr(sizeof(Tp) <= sizeof(Low)) {
126 return static_cast<Tp>(low);
127 } else {
128 return static_cast<Tp>(low) | (static_cast<Tp>(high) << (sizeof(Low) * 8));
129 }
130 };
131
132#if defined(CE_LARGE_INTEGER_HAS_INT128)
134 using Native = std::conditional_t<std::is_signed<Hi>::value, __int128, unsigned __int128>;
135
139 constexpr LargeInteger(__int128 value) noexcept // NOLINT explicit
140 : LargeInteger(Hi(value >> (sizeof(Low) * 8)), Low(value)) {}
141
146 [[nodiscard]] constexpr explicit operator unsigned __int128() const noexcept {
147 return static_cast<unsigned __int128>(high) << (sizeof(Low) * 8) | static_cast<unsigned __int128>(low);
148 }
149
153 constexpr LargeInteger(unsigned __int128 value) noexcept // NOLINT explicit
154 : LargeInteger(static_cast<__int128>(value)) {}
155
160 [[nodiscard]] constexpr explicit operator __int128() const noexcept { return static_cast<__int128>(static_cast<unsigned __int128>(*this)); }
161#endif
162
166 constexpr LargeInteger(float value) noexcept // NOLINT explicit
167#if defined(CE_LARGE_INTEGER_HAS_INT128)
168 : LargeInteger(static_cast<Native>(value)){}
169#else
170 : LargeInteger(Hi(std::ldexp(value, -static_cast<int>(sizeof(Low) * 8))) - (value < 0), Low(value)) {
171 }
172#endif
173
176 [[nodiscard]] constexpr explicit
177 operator float() const noexcept {
178#if defined(CE_LARGE_INTEGER_HAS_INT128)
179 return static_cast<float>(static_cast<Native>(*this));
180#else
181 return static_cast<float>(static_cast<long double>(*this));
182#endif
183 }
184
188 constexpr LargeInteger(double value) noexcept // NOLINT explicit
189#if defined(CE_LARGE_INTEGER_HAS_INT128)
190 : LargeInteger(static_cast<Native>(value)){}
191#else
192 : LargeInteger(Hi(std::ldexp(value, -static_cast<int>(sizeof(Low) * 8))) - (value < 0), Low(value)) {
193 }
194#endif
195
198 [[nodiscard]] constexpr explicit
199 operator double() const noexcept {
200#if defined(CE_LARGE_INTEGER_HAS_INT128)
201 return static_cast<double>(static_cast<Native>(*this));
202#else
203 return static_cast<double>(static_cast<long double>(*this));
204#endif
205 }
206
210 constexpr LargeInteger(long double value) noexcept // NOLINT explicit
211#if defined(CE_LARGE_INTEGER_HAS_INT128)
212 : LargeInteger(static_cast<Native>(value)){}
213#else
214 : LargeInteger(Hi(std::ldexp(value, -static_cast<int>(sizeof(Low) * 8))) - (value < 0), Low(value)) {
215 }
216#endif
217
220 [[nodiscard]] constexpr explicit
221 operator long double() const noexcept {
222 using Tp = long double;
223#if defined(CE_LARGE_INTEGER_HAS_INT128)
224 return static_cast<Tp>(static_cast<Native>(*this));
225#else
226 if constexpr(std::is_signed<Hi>::value) {
227 using UnsignedType = typename std::make_unsigned<LargeInteger>::type;
228 return high < 0 ? -static_cast<Tp>(UnsignedType(-*this)) : +static_cast<Tp>(UnsignedType(+*this));
229 } else {
230 return std::ldexp(Tp(high), sizeof(Low) * 8) + Tp(low);
231 }
232#endif
233 }
234
235 public:
239 [[nodiscard]] constexpr explicit operator bool() const noexcept { return high || low; }
240 };
241
244
247
248 template<typename Tp> static constexpr Tp halfMask = (Tp(1) << (4 * sizeof(Tp))) - Tp(1);
249 template<typename Tp> static constexpr size_t bits = sizeof(Tp) * 8;
250 template<typename Tp> static constexpr size_t halfBits = bits<Tp> / 2;
251
252 template<typename T>
253 constexpr void multwide(T a, T b, T& hi, T &lo)
254 {
255 T a_lo = a & halfMask<T>;
256 T a_hi = a >> halfBits<T>;
257 T b_lo = b & halfMask<T>;
258 T b_hi = b >> halfBits<T>;
259
260 T p0 = a_lo * b_lo;
261 T p1 = a_lo * b_hi;
262 T p2 = a_hi * b_lo;
263 T p3 = a_hi * b_hi;
264
265 T cy = (((p0 >> halfBits<T>) + (p1 & halfMask<T>) + (p2 & halfMask<T>)) >> halfBits<T>);
266
267 lo = p0 + (p1 << halfBits<T>) + (p2 << halfBits<T>);
268 hi = p3 + (p1 >> halfBits<T>) + (p2 >> halfBits<T>) + cy;
269 }
270
272 const T a_lo = a.low;
273 const T a_hi = a.high;
274 const T b_lo = b.low;
275 const T b_hi = b.high;
276
281
282 const LargeInteger<T, T> cy = ((p0 >> bits<T>) + p1 + p2) >> bits<T>;
283
284 lo = p0 + (p1 << bits<T>)+(p2 << bits<T>);
285 hi = p3 + (p1 >> bits<T>)+(p2 >> bits<T>)+cy;
286 }
287
288 template<typename T> constexpr void mult128(T N, T M, T& Ans) {
289 mult64to128(N.low, M.low, Ans.high, Ans.low);
290 Ans.high += (N.high * M.low) + (N.low * M.high);
291 }
292
293 template<typename U> constexpr void mult128to256(U N, U M, U& H, U& L) {
294 multwide(N.high, M.high, H.high, H.low);
295 multwide(N.low, M.low, L.high, L.low);
296
297 U T;
298 multwide(N.high, M.low, T.high, T.low);
299 L.high += T.low;
300 if(L.high < T.low) // if L.high overflowed
301 {
302 ++H;
303 }
304 H.low += T.high;
305 if(H.low < T.high) // if H.low overflowed
306 {
307 ++H.high;
308 }
309
310 multwide(N.low, M.high, T.high, T.low);
311 L.high += T.low;
312 if(L.high < T.low) // if L.high overflowed
313 {
314 ++H;
315 }
316 H.low += T.high;
317 if(H.low < T.high) // if H.low overflowed
318 {
319 ++H.high;
320 }
321 }
322
323 // clang-format off
324 inline namespace literals {
325 namespace impl_ {
326 template<char _Ch, int _Rad>
327 struct static_digit : std::integral_constant<
328 int, '0' <= _Ch && _Ch <= '9'
329 ? _Ch - '0'
330 : 'a' <= _Ch && _Ch <= 'z'
331 ? _Ch - 'a' + 10
332 : 'A' <= _Ch && _Ch <= 'Z' ? _Ch - 'A' + 10 : _Rad> {
333 static_assert(_Rad > static_digit::value, "character not a digit");
334 };
335
336 template<typename, int, char...>
337 struct int128_literal_radix;
338
339 template<typename Tp, int _Rad, char _Ch>
340 struct int128_literal_radix<Tp, _Rad, _Ch> {
341 constexpr operator Tp() const { return Tp(static_digit<_Ch, _Rad>::value); } // NOLINT explicit
342
343 constexpr Tp operator()(Tp v) const { return v * Tp(_Rad) + static_cast<Tp>(*this); }
344 };
345
346 template<typename Tp, int _Rad, char _Ch, char... _Args>
347 struct int128_literal_radix<Tp, _Rad, _Ch, _Args...> {
348 int128_literal_radix<Tp, _Rad, _Ch> _Cur; // NOLINT(misc-non-private-member-variables-in-classes)
349 int128_literal_radix<Tp, _Rad, _Args...> _Tgt; // NOLINT(misc-non-private-member-variables-in-classes)
350
351 constexpr operator Tp() const { return _Tgt(_Cur); }; // NOLINT explicit
352
353 constexpr Tp operator()(Tp v) const { return _Tgt(_Cur(v)); };
354 };
355
356 template<typename Tp, char... _Args>
357 struct int128_literal : int128_literal_radix<Tp, 10, _Args...> {};
358 template<typename Tp>
359 struct int128_literal<Tp, '0'> : int128_literal_radix<Tp, 10, '0'> {};
360 template<typename Tp, char... _Args>
361 struct int128_literal<Tp, '0', _Args...> : int128_literal_radix<Tp, 8, _Args...> {};
362 template<typename Tp, char... _Args>
363 struct int128_literal<Tp, '0', 'x', _Args...> : int128_literal_radix<Tp, 16, _Args...> {};
364 template<typename Tp, char... _Args>
365 struct int128_literal<Tp, '0', 'X', _Args...> : int128_literal_radix<Tp, 16, _Args...> {};
366 template<typename Tp, char... _Args>
367 struct int128_literal<Tp, '0', 'b', _Args...> : int128_literal_radix<Tp, 2, _Args...> {};
368 template<typename Tp, char... _Args>
369 struct int128_literal<Tp, '0', 'B', _Args...> : int128_literal_radix<Tp, 2, _Args...> {};
370 }
371
372 template<char... _Args>
373 constexpr UInt128 operator"" _u128() {
374 return impl_::int128_literal<UInt128, _Args...>();
375 }
376
377 template<char... _Args>
378 constexpr Int128 operator"" _i128() {
379 return impl_::int128_literal<Int128, _Args...>();
380 }
381 }
382 // clang-format on
383
384 template<typename> struct LargeIntegerCLZHelper;
385
386#if defined(__cpp_lib_bitops)
387 template<typename T> struct LargeIntegerCLZHelper {
388 static constexpr int clz(T val) { return std::countl_zero(val); }
389 };
390#elif CE_COMPILER_CLANG || CE_COMPILER_GNUC
391 template<> struct LargeIntegerCLZHelper<unsigned char> {
392 static constexpr int clz(unsigned int val) { return __builtin_clzs(val) - 8; }
393 };
394
395 template<> struct LargeIntegerCLZHelper<unsigned short> {
396 static constexpr int clz(unsigned int val) { return __builtin_clzs(val); }
397 };
398
399 template<> struct LargeIntegerCLZHelper<unsigned int> {
400 static constexpr int clz(unsigned int val) { return __builtin_clz(val); }
401 };
402
403 template<> struct LargeIntegerCLZHelper<unsigned long> {
404 static constexpr int clz(unsigned long val) { return __builtin_clzl(val); }
405 };
406
407 template<> struct LargeIntegerCLZHelper<unsigned long long> {
408 static constexpr int clz(unsigned long long val) { return __builtin_clzll(val); }
409 };
410#elif CE_COMPILER_MSVC
411 template<> struct LargeIntegerCLZHelper<unsigned char> {
412 static int clz(unsigned char val) { return int(__lzcnt16(val) - 8); }
413 };
414
415 template<> struct LargeIntegerCLZHelper<unsigned short> {
416 static int clz(unsigned short val) { return int(__lzcnt16(val)); }
417 };
418
419 template<> struct LargeIntegerCLZHelper<unsigned int> {
420 static int clz(unsigned int val) { return int(__lzcnt(val)); }
421 };
422
423 template<> struct LargeIntegerCLZHelper<unsigned __int64> {
424 static int clz(unsigned __int64 val) { return int(__lzcnt64(val)); }
425 };
426#else
427#error Unsupported compiler!
428#endif
429
430 template<typename High, typename Low> struct LargeIntegerCLZHelper<LargeInteger<High, Low>> {
431 static constexpr int clz(LargeInteger<High, Low> val) {
432 return val.high ? LargeIntegerCLZHelper<Low>::clz(Low(val.high)) : 4 * sizeof(val) + LargeIntegerCLZHelper<Low>::clz(val.low);
433 }
434 };
435
436 template<typename Hi, typename Low>
437 static LargeInteger<Hi, Low>& slowdiv(LargeInteger<Hi, Low>& dividend, LargeInteger<Hi, Low> divisor, LargeInteger<Hi, Low>& quot) {
438 quot = LargeInteger<Hi, Low>(0);
439 if(dividend < divisor)
440 return dividend;
441 if(dividend.high == 0) { // (0,x) / ???
442 quot.low = dividend.low / divisor.low;
443 dividend.low %= divisor.low;
444 return dividend;
445 }
446 auto zend = LargeIntegerCLZHelper<LargeInteger<Hi, Low>>::clz(dividend);
447 auto zsor = LargeIntegerCLZHelper<LargeInteger<Hi, Low>>::clz(divisor);
448 if(zend > zsor)
449 return dividend;
450 for(zsor -= zend, divisor <<= zsor;; divisor >>= 1, quot <<= 1) {
451 if(dividend >= divisor) {
452 dividend -= divisor;
453 quot |= LargeInteger<Hi, Low>(1);
454 }
455 if(!zsor--)
456 return dividend;
457 }
458 }
459
466 template<typename Hi, typename Low>
467 [[nodiscard]] constexpr LargeInteger<Hi, Low> operator+(LargeInteger<Hi, Low> lhs, typename LargeInteger<Hi, Low>::Self rhs) noexcept {
468 // no worry for unsigned type, won't be optimized if overflow
469 return {Hi(lhs.high + rhs.high + (lhs.low + rhs.low < lhs.low)), static_cast<Low>(lhs.low + rhs.low)};
470 }
471
478 template<typename Hi, typename Low>
479 [[nodiscard]] constexpr LargeInteger<Hi, Low> operator-(LargeInteger<Hi, Low> lhs, typename LargeInteger<Hi, Low>::Self rhs) noexcept {
480 return {Hi(lhs.high - rhs.high - (lhs.low < rhs.low)), static_cast<Low>(lhs.low - rhs.low)};
481 }
482
489 template<typename Hi, typename Low>
490 [[nodiscard]] constexpr LargeInteger<Hi, Low> operator*(LargeInteger<Hi, Low> lhs, typename LargeInteger<Hi, Low>::Self rhs) noexcept {
491 return LargeInteger<Hi, Low>(Hi(Hi(lhs.low) * rhs.high + Hi(rhs.low) * lhs.high) + Hi(lhs.low >> halfBits<Low>) * Hi(rhs.low >> halfBits<Low>),
492 (lhs.low & halfMask<Low>)*(rhs.low & halfMask<Low>)) +
493 (LargeInteger<Hi, Low>(Hi(0), (lhs.low >> halfBits<Low>)*(rhs.low & halfMask<Low>)) << halfBits<Low>)+(
494 LargeInteger<Hi, Low>(Hi(0), (rhs.low >> halfBits<Low>)*(lhs.low & halfMask<Low>)) << halfBits<Low>);
495
496// if constexpr(std::is_signed<Hi>::value) {
497// using UnsignedHi = std::make_unsigned<Hi>::type;
498// using Unsigned = std::make_unsigned<LargeInteger<Hi, Low>>::type;
499//
500// bool isNegative = false;
501// if (lhs.high < Hi(0)) {
502// lhs = -lhs;
503// isNegative = !isNegative;
504// }
505//
506// if (rhs.high < Hi(0)) {
507// rhs = -rhs;
508// isNegative = !isNegative;
509// }
510//
511// const Unsigned result = Unsigned(UnsignedHi(lhs.high), Low(lhs.low)) * Unsigned(UnsignedHi(rhs.high), Low(rhs.low));
512// if (isNegative) {
513// return LargeInteger<Hi, Low>(Hi(result.high), result.low);
514// }
515// return LargeInteger<Hi, Low>(Hi(result.high), result.low);
516// } else {
517// LargeInteger<Hi, Low> high, low;
518// multwide(lhs, rhs, high, low);
519// return low;
520// }
521// if constexpr(std::is_signed<Hi>::value) {
525// retrn LargeInteger<Hi, Low>(-lhs, -rhs);
526// } else {
527// Low a_lo = lhs.low;
528// Low a_hi = lhs.high;
529// Low b_lo = rhs.low;
530// Low b_hi = rhs.high;
531//
532// Low p0 = a_lo * b_lo;
533// Low p1 = a_lo * b_hi;
534// Low p2 = a_hi * b_lo;
535// Low p3 = a_hi * b_hi;
536//
537// LargeInteger<Hi, Low> cy = (((LargeInteger<Hi, Low>(Hi(0), p0) >> bits<Low>) + (LargeInteger<Hi, Low>(Hi(0), p1)) + LargeInteger<Hi, Low>(Hi(0), p2)) >> bits<Low>);
538//
539// return LargeInteger<Hi, Low>(
540// /* hi: */ p3 + (p1 >> halfBits<Low>) + (p2 >> halfBits<Low>),
541// /* lo: */ p0 + (p1 << halfBits<Low>) + (p2 << halfBits<Low>)
542// ) + cy;
543// }
544
545// const auto multiply = [](const Low& a, const Low& b) -> LargeInteger<Hi, Low> {
546// Low a_lo = a & halfMask<Low>;
547// Low a_hi = a >> halfBits<Low>;
548// Low b_lo = b & halfMask<Low>;
549// Low b_hi = b >> halfBits<Low>;
550//
551// Low a_x_b_hi = a_hi * b_hi;
552// Low a_x_b_mid = a_hi * b_lo;
553// Low b_x_a_mid = b_hi * a_lo;
554// Low a_x_b_lo = a_lo * b_lo;
555//
556// Low carry_bit = ((a_x_b_mid & halfMask<Low>) + (b_x_a_mid & halfMask<Low>) + (a_x_b_lo >> halfBits<Low>)) >> halfBits<Low>;
557//
558// Low multlo = ((a_hi << halfBits<Low>)+a_lo) * ((b_hi << halfBits<Low>)+b_lo);
559// Low multhi = a_x_b_hi + (a_x_b_mid >> halfBits<Low>)+(b_x_a_mid >> halfBits<Low>)+carry_bit;
560//
561// return LargeInteger<Hi, Low>(multhi, multlo);
562// };
563
564// Low a_lo = lhs.low;
565// Low a_hi = lhs.high;
566// Low b_lo = rhs.low;
567// Low b_hi = rhs.high;
568//
569// Low a_x_b_hi = a_hi * b_hi;
570// Low a_x_b_mid = a_hi * b_lo;
571// Low b_x_a_mid = b_hi * a_lo;
572// Low a_x_b_lo = a_lo * b_lo;
573//
574// Low carry_bit = ((a_x_b_mid & halfMask<Low>) + (b_x_a_mid & halfMask<Low>) + (a_x_b_lo >> halfBits<Low>)) >> halfBits<Low>;
575//
576// Low multlo = ((a_hi << halfBits<Low>)+a_lo) * ((b_hi << halfBits<Low>)+b_lo);
577// Low multhi = a_x_b_hi + (a_x_b_mid >> halfBits<Low>)+(b_x_a_mid >> halfBits<Low>)+carry_bit;
578
579// LargeInteger<Hi, Low> result = multiply();
580// mult64to128(N.low, M.low, Ans.high, Ans.low);
581// return multiply(lhs.low, rhs.low) + multiply(lhs.high, rhs.low) + multiply(lhs.low, rhs.high) + multiply(lhs.high, rhs.high);
582
583// Ans.high += (N.high * M.low) + (N.low * M.high);
584
585
586 // Hi high = lhs.high * rhs.high;
587// Low low = lhs.low * rhs.low;
588//
589// return LargeInteger<Hi, Low>(high, low);
590
591
592 // LargeInteger<Hi, Low> result = LargeInteger<Hi, Low>(Hi(Hi(lhs.low) * rhs.high + Hi(rhs.low) * lhs.high) + Hi(lhs.low >> halfBits<Low>) * Hi(rhs.low >> halfBits<Low>),
593// (lhs.low & halfMask<Low>)*(rhs.low & halfMask<Low>)) +
594// (LargeInteger<Hi, Low>(Hi(0), (lhs.low >> halfBits<Low>)*(rhs.low & halfMask<Low>)) << halfBits<Low>)+(
595// LargeInteger<Hi, Low>(Hi(0), (rhs.low >> halfBits<Low>)*(lhs.low & halfMask<Low>)) << halfBits<Low>);
596//
597// result.high--;
598//
599// return result;
600
601 // const bool negate = (lhs.high < Hi(0)) != (rhs.high < Hi(0));
602//
603// if (lhs.high < Hi(0)) lhs = -lhs;
604// Low int1Hi = Low(lhs.high) >> halfBits<Low>;
605// Low int1Lo = Low(lhs.low & halfMask<Low>);
606//
607// if (rhs.high < Hi(0)) rhs = -rhs;
608// Low int2Hi = Low(rhs.high) >> halfBits<Low>;
609// Low int2Lo = Low(rhs.low & halfMask<Low>);
610//
611// Low a = int1Hi * int2Hi;
612// Low b = int1Lo * int2Lo;
613// Low c = int1Hi * int2Lo + int1Lo * int2Hi;
614//
615// LargeInteger<Hi, Low> tmp;
616// tmp.high = Hi(a + (c >> halfBits<Low>));
617// tmp.low = Low(c << halfBits<Low>);
618// tmp.low += Low(b);
619// if (tmp.low < b) tmp.high++;
620// if (negate) tmp = -tmp;
621// return tmp;
622
623
624// if constexpr(std::is_signed<Hi>::value) {
625// using UnsignedHi = std::make_unsigned<Hi>::type;
626// using Unsigned = std::make_unsigned<LargeInteger<Hi, Low>>::type;
627//
628// bool isNegative = false;
629// if (lhs.high < Hi(0)) {
630// lhs = -lhs;
631// isNegative = !isNegative;
632// }
633//
634// if (rhs.high < Hi(0)) {
635// rhs = -rhs;
636// isNegative = !isNegative;
637// }
638//
639// const Unsigned result = Unsigned(UnsignedHi(lhs.high), Low(lhs.low)) * Unsigned(UnsignedHi(rhs.high), Low(rhs.low));
640//
641// if (isNegative) {
642// return LargeInteger<Hi, Low>(Hi(result.high), result.low);
643// }
644// return LargeInteger<Hi, Low>(Hi(result.high), result.low);;
645//
646// } else {
647// return LargeInteger<Hi, Low>(Hi(Hi(lhs.low) * rhs.high + Hi(rhs.low) * lhs.high) + Hi(lhs.low >> halfBits<Low>) * Hi(rhs.low >> halfBits<Low>),
648// (lhs.low & halfMask<Low>)*(rhs.low & halfMask<Low>)) +
649// (LargeInteger<Hi, Low>(Hi(0), (lhs.low >> halfBits<Low>)*(rhs.low & halfMask<Low>)) << halfBits<Low>)+(
650// LargeInteger<Hi, Low>(Hi(0), (rhs.low >> halfBits<Low>)*(lhs.low & halfMask<Low>)) << halfBits<Low>);
651// }
652
653// bool isNegative = false;
654// if (lhs.high < Hi(0)) {
655// lhs = -lhs;
656// isNegative = !isNegative;
657// }
658//
659// if (rhs.high < Hi(0)) {
660// rhs = -rhs;
661// isNegative = !isNegative;
662// }
663//
664// LargeInteger<UnsignedHi, Low> result = LargeInteger<UnsignedHi, Low>(UnsignedHi(UnsignedHi(lhs.low) * rhs.high + UnsignedHi(rhs.low) * lhs.high) +
665// UnsignedHi(lhs.low >> halfBits<Low>) * UnsignedHi(rhs.low >> halfBits<Low>),
666// (lhs.low & halfMask<Low>)*(rhs.low & halfMask<Low>)) +
667// (LargeInteger<UnsignedHi, Low>(UnsignedHi(0), (lhs.low >> halfBits<Low>)*(rhs.low & halfMask<Low>)) << halfBits<Low>)+(
668// LargeInteger<UnsignedHi, Low>(UnsignedHi(0), (rhs.low >> halfBits<Low>)*(lhs.low & halfMask<Low>)) << halfBits<Low>);
669//
670// if (isNegative) {
671// return LargeInteger<Hi, Low>(-Hi(result.hi), result.low);
672// result = -result;
673// }
674// return result;
675 }
676
683 template<typename Hi, typename Low>
684 [[nodiscard]] constexpr LargeInteger<Hi, Low> operator/(LargeInteger<Hi, Low> lhs, typename LargeInteger<Hi, Low>::Self rhs) noexcept {
685 if constexpr(std::is_unsigned_v<Hi>) {
686 // if (!divisor_) return {!!dividend_ / !!divisor_};
687 // // raise signal SIGFPE
688 LargeInteger<Hi, Low> quot(0);
689 slowdiv(lhs, rhs, quot);
690 return quot;
691 } else {
692 using UT = LargeInteger<typename std::make_unsigned<Hi>::type, Low>;
693
694 bool nneg_ = lhs.high < 0;
695 bool dneg_ = rhs.high < 0;
696 UT a = UT(nneg_ ? -lhs : lhs);
697 UT b = UT(dneg_ ? -rhs : rhs);
698
699 UT quot(0);
700 slowdiv(a, b, quot);
701
702 return LargeInteger<Hi, Low>(nneg_ ^ dneg_ ? -quot : quot);
703 }
704 }
705
712 template<typename Hi, typename Low>
713 [[nodiscard]] constexpr LargeInteger<Hi, Low> operator%(LargeInteger<Hi, Low> lhs, typename LargeInteger<Hi, Low>::Self rhs) noexcept {
714 if constexpr(std::is_unsigned_v<Hi>) {
715 // if(!divisor_ && !dividend_) raise(SIGFPE);
716 LargeInteger<Hi, Low> quot(0);
717 return slowdiv(lhs, rhs, quot);
718 } else {
719 using UT = LargeInteger<typename std::make_unsigned<Hi>::type, Low>;
720 bool neg_ = lhs.high < 0;
721
722 UT a = UT(neg_ ? -lhs : lhs);
723 UT b = UT(rhs.high < 0 ? -rhs : rhs);
724
725 UT quot(0);
726 auto rem = slowdiv(a, b, quot);
727
728 return LargeInteger<Hi, Low>(neg_ ? -rem : rem);
729 }
730 }
731
738 template<typename Hi, typename Low>
739 [[nodiscard]] constexpr LargeInteger<Hi, Low> operator&(LargeInteger<Hi, Low> lhs, typename LargeInteger<Hi, Low>::Self rhs) noexcept {
740 return {static_cast<Hi>(lhs.high & rhs.high), static_cast<Low>(lhs.low & rhs.low)};
741 }
742
749 template<typename Hi, typename Low>
750 [[nodiscard]] constexpr LargeInteger<Hi, Low> operator|(LargeInteger<Hi, Low> lhs, typename LargeInteger<Hi, Low>::Self rhs) noexcept {
751 return {static_cast<Hi>(lhs.high | rhs.high), static_cast<Low>(lhs.low | rhs.low)};
752 }
753
760 template<typename Hi, typename Low>
761 [[nodiscard]] constexpr LargeInteger<Hi, Low> operator^(LargeInteger<Hi, Low> lhs, typename LargeInteger<Hi, Low>::Self rhs) noexcept {
762 return {static_cast<Hi>(lhs.high ^ rhs.high), static_cast<Low>(lhs.low ^ rhs.low)};
763 }
764
771 template<typename Hi, typename Low> [[nodiscard]] constexpr LargeInteger<Hi, Low> operator<<(LargeInteger<Hi, Low> lhs, int rhs) noexcept {
772 // [64,127], 64 {low << 0, 0}
773 constexpr Low bitsMinusOne = bits<Low> - 1;
774 return Low(rhs) & bits<Low> ? LargeInteger<Hi, Low>(Hi(lhs.low << int(Low(rhs) & bitsMinusOne)), Low(0))
775 : Low(rhs) & bitsMinusOne
776 ? LargeInteger<Hi, Low>(Hi((Low(lhs.high) << int(Low(rhs) & bitsMinusOne)) | (lhs.low >> int(Low(bits<Low>) - (Low(rhs) & bitsMinusOne)))),
777 lhs.low << int(Low(rhs) & bitsMinusOne))
778 : lhs;
779 }
780
787 template<typename Hi, typename Low> [[nodiscard]] constexpr LargeInteger<Hi, Low> operator>>(LargeInteger<Hi, Low> lhs, int rhs) noexcept {
788 using T = LargeInteger<Hi, Low>;
789 constexpr Low bitsMinusOne = bits<Low> - 1;
790
791 // clang-format off
792 if constexpr(std::is_signed<T>::value) {
793 return Low(rhs) & bits<Low> ? T(Hi(lhs.high < 0 ? -1 : 0),
794 Low(lhs.high >> int(Low(rhs) & bitsMinusOne)))
795 : // NOLINT
796 Low(rhs) & bitsMinusOne
797 ? T(Hi(lhs.high >> int(Low(rhs) & bitsMinusOne)), // NOLINT signed
798 // shift
799 Low(Hi(lhs.high) << int(Low(bits<Low>) - (Low(rhs) & bitsMinusOne)) |
800 Hi(lhs.low >> int(Low(rhs) & bitsMinusOne))))
801 : lhs;
802 } else {
803 return Low(rhs) & bits<Low> ? T(0, lhs.high >> int(Low(rhs) & bitsMinusOne))
804 : Low(rhs) & bitsMinusOne
805 ? T(lhs.high >> int(Low(rhs) & bitsMinusOne),
806 (lhs.high << int(Low(bits<Low>) - (Low(rhs) & bitsMinusOne)) |
807 Hi(lhs.low >> int(Low(rhs) & bitsMinusOne))))
808 : lhs;
809 }
810 // clang-format on
811 }
812
813#if defined(CE_LARGE_INTEGER_HAS_INT128)
818 [[nodiscard]] inline constexpr Int128 operator+(Int128 lhs, Int128 rhs) noexcept {
819 using Native = __int128;
820 return static_cast<Native>(lhs) + static_cast<Native>(rhs);
821 }
822
827 [[nodiscard]] inline constexpr UInt128 operator+(UInt128 lhs, UInt128 rhs) noexcept {
828 using Native = unsigned __int128;
829 return static_cast<Native>(lhs) + static_cast<Native>(rhs);
830 }
831
836 [[nodiscard]] inline constexpr Int128 operator-(Int128 lhs, Int128 rhs) noexcept {
837 using Native = __int128;
838 return static_cast<Native>(lhs) - static_cast<Native>(rhs);
839 }
840
845 [[nodiscard]] inline constexpr UInt128 operator-(UInt128 lhs, UInt128 rhs) noexcept {
846 using Native = unsigned __int128;
847 return static_cast<Native>(lhs) - static_cast<Native>(rhs);
848 }
849
854 [[nodiscard]] inline constexpr Int128 operator*(Int128 lhs, Int128 rhs) noexcept {
855 using Native = __int128;
856 return static_cast<Native>(lhs) * static_cast<Native>(rhs);
857 }
858
863 [[nodiscard]] inline constexpr UInt128 operator*(UInt128 lhs, UInt128 rhs) noexcept {
864 using Native = unsigned __int128;
865 return static_cast<Native>(lhs) * static_cast<Native>(rhs);
866 }
867
872 [[nodiscard]] inline constexpr Int128 operator/(Int128 lhs, Int128 rhs) noexcept {
873 using Native = __int128;
874 return static_cast<Native>(lhs) / static_cast<Native>(rhs);
875 };
876
881 [[nodiscard]] inline constexpr UInt128 operator/(UInt128 lhs, UInt128 rhs) noexcept {
882 using Native = unsigned __int128;
883 return static_cast<Native>(lhs) / static_cast<Native>(rhs);
884 };
885
890 [[nodiscard]] inline constexpr Int128 operator%(Int128 lhs, Int128 rhs) noexcept {
891 using Native = __int128;
892 return static_cast<Native>(lhs) % static_cast<Native>(rhs);
893 }
894
899 [[nodiscard]] inline constexpr UInt128 operator%(UInt128 lhs, UInt128 rhs) noexcept {
900 using Native = unsigned __int128;
901 return static_cast<Native>(lhs) % static_cast<Native>(rhs);
902 }
903
907 [[nodiscard]] inline constexpr Int128 operator&(Int128 lhs, Int128 rhs) noexcept {
908 using Native = __int128;
909 return static_cast<Native>(lhs) & static_cast<Native>(rhs);
910 }
911
915 [[nodiscard]] inline constexpr UInt128 operator&(UInt128 lhs, UInt128 rhs) noexcept {
916 using Native = unsigned __int128;
917 return static_cast<Native>(lhs) & static_cast<Native>(rhs);
918 }
919
923 [[nodiscard]] inline constexpr Int128 operator|(Int128 lhs, Int128 rhs) noexcept {
924 using Native = __int128;
925 return static_cast<Native>(lhs) | static_cast<Native>(rhs);
926 }
927
931 [[nodiscard]] inline constexpr UInt128 operator|(UInt128 lhs, UInt128 rhs) noexcept {
932 using Native = unsigned __int128;
933 return static_cast<Native>(lhs) | static_cast<Native>(rhs);
934 }
935
939 [[nodiscard]] inline constexpr Int128 operator^(Int128 lhs, Int128 rhs) noexcept {
940 using Native = __int128;
941 return static_cast<Native>(lhs) ^ static_cast<Native>(rhs);
942 }
943
947 [[nodiscard]] inline constexpr UInt128 operator^(UInt128 lhs, UInt128 rhs) noexcept {
948 using Native = unsigned __int128;
949 return static_cast<Native>(lhs) ^ static_cast<Native>(rhs);
950 }
951
956 [[nodiscard]] inline constexpr Int128 operator<<(Int128 lhs, int rhs) noexcept {
957 using Native = __int128;
958 return static_cast<Native>(lhs) << rhs;
959 }
960
965 [[nodiscard]] inline constexpr UInt128 operator<<(UInt128 lhs, int rhs) noexcept {
966 using Native = unsigned __int128;
967 return static_cast<Native>(lhs) << rhs;
968 }
969
974 [[nodiscard]] inline constexpr Int128 operator>>(Int128 lhs, int rhs) noexcept {
975 using Native = __int128;
976 return static_cast<Native>(lhs) >> rhs;
977 }
978
983 [[nodiscard]] inline constexpr UInt128 operator>>(UInt128 lhs, int rhs) noexcept {
984 using Native = unsigned __int128;
985 return static_cast<Native>(lhs) >> rhs;
986 }
987#endif
988
989 // ---------------------------------------------------------------------------------------------
990
995 template<typename Hi, typename Low> [[nodiscard]] constexpr LargeInteger<Hi, Low> operator+(LargeInteger<Hi, Low> lhs) noexcept { return lhs; }
996
1002 template<typename Hi, typename Low> [[nodiscard]] constexpr LargeInteger<Hi, Low> operator-(LargeInteger<Hi, Low> lhs) noexcept {
1003 CE_DISABLE_WARNING_PUSH
1004 CE_DISABLE_WARNING_UNSIGNED_UNARY_MINUS
1005 return LargeInteger<Hi, Low>(-lhs.high - (lhs.low == 0 ? Hi(1) : Hi(0)), lhs.low);
1006 CE_DISABLE_WARNING_POP
1007 }
1008
1014 template<typename Hi, typename Low> [[nodiscard]] constexpr LargeInteger<Hi, Low> operator~(LargeInteger<Hi, Low> lhs) noexcept {
1015 return LargeInteger<Hi, Low>(~lhs.high, ~lhs.low);
1016 }
1017
1023 template<typename Hi, typename Low> [[nodiscard]] constexpr bool operator!(LargeInteger<Hi, Low> lhs) noexcept { return !bool(lhs); }
1024
1030 template<typename Hi, typename Low> LargeInteger<Hi, Low>& operator++(LargeInteger<Hi, Low>& lhs) noexcept { return lhs = lhs + LargeInteger<Hi, Low>(1); }
1031
1037 template<typename Hi, typename Low>
1038 LargeInteger<Hi, Low> // NOLINT(cert-dcl21-cpp)
1039 operator++(LargeInteger<Hi, Low>& lhs, int) noexcept {
1040 LargeInteger tmp = lhs;
1041 ++lhs;
1042 return tmp;
1043 }
1044
1050 template<typename Hi, typename Low> LargeInteger<Hi, Low>& operator--(LargeInteger<Hi, Low>& lhs) noexcept { return lhs = lhs - LargeInteger<Hi, Low>(1); }
1051
1057 template<typename Hi, typename Low>
1058 LargeInteger<Hi, Low> // NOLINT(cert-dcl21-cpp)
1059 operator--(LargeInteger<Hi, Low>& lhs, int) noexcept {
1060 LargeInteger tmp = lhs;
1061 --lhs;
1062 return tmp;
1063 }
1064
1065#if defined(CE_LARGE_INTEGER_HAS_INT128)
1069 [[nodiscard]] inline constexpr Int128 operator-(Int128 lhs) noexcept {
1070 using Native = __int128;
1071 return -static_cast<Native>(lhs);
1072 }
1073
1077 [[nodiscard]] inline constexpr UInt128 operator-(UInt128 lhs) noexcept {
1078 using Native = unsigned __int128;
1079 return -static_cast<Native>(lhs);
1080 }
1081
1085 [[nodiscard]] inline constexpr Int128 operator~(Int128 lhs) noexcept {
1086 using Native = __int128;
1087 return ~static_cast<Native>(lhs);
1088 }
1089
1093 [[nodiscard]] inline constexpr UInt128 operator~(UInt128 lhs) noexcept {
1094 using Native = unsigned __int128;
1095 return ~static_cast<Native>(lhs);
1096 }
1097#endif
1098
1099 // ---------------------------------------------------------------------------------------------
1100
1107 template<typename Hi, typename Low>
1108 constexpr LargeInteger<Hi, Low>& operator+=(LargeInteger<Hi, Low>& lhs, typename LargeInteger<Hi, Low>::Self rhs) noexcept {
1109 return lhs = lhs + rhs;
1110 }
1111
1118 template<typename Hi, typename Low>
1119 constexpr LargeInteger<Hi, Low>& operator-=(LargeInteger<Hi, Low>& lhs, typename LargeInteger<Hi, Low>::Self rhs) noexcept {
1120 return lhs = lhs - rhs;
1121 }
1122
1129 template<typename Hi, typename Low>
1130 constexpr LargeInteger<Hi, Low>& operator*=(LargeInteger<Hi, Low>& lhs, typename LargeInteger<Hi, Low>::Self rhs) noexcept {
1131 return lhs = lhs * rhs;
1132 }
1133
1140 template<typename Hi, typename Low>
1141 constexpr LargeInteger<Hi, Low>& operator/=(LargeInteger<Hi, Low>& lhs, typename LargeInteger<Hi, Low>::Self rhs) noexcept {
1142 return lhs = lhs / rhs;
1143 }
1144
1152 template<typename Hi, typename Low>
1153 constexpr LargeInteger<Hi, Low>& operator%=(LargeInteger<Hi, Low>& lhs, typename LargeInteger<Hi, Low>::Self rhs) noexcept {
1154 return lhs = lhs % rhs;
1155 }
1156
1163 template<typename Hi, typename Low> constexpr LargeInteger<Hi, Low>& operator<<=(LargeInteger<Hi, Low>& lhs, int rhs) noexcept { return lhs = lhs << rhs; }
1164
1171 template<typename Hi, typename Low> constexpr LargeInteger<Hi, Low>& operator>>=(LargeInteger<Hi, Low>& lhs, int rhs) noexcept { return lhs = lhs >> rhs; }
1172
1179 template<typename Hi, typename Low>
1180 constexpr LargeInteger<Hi, Low>& operator&=(LargeInteger<Hi, Low>& lhs, typename LargeInteger<Hi, Low>::Self rhs) noexcept {
1181 return lhs = lhs & rhs;
1182 }
1183
1190 template<typename Hi, typename Low>
1191 constexpr LargeInteger<Hi, Low>& operator|=(LargeInteger<Hi, Low>& lhs, typename LargeInteger<Hi, Low>::Self rhs) noexcept {
1192 return lhs = lhs | rhs;
1193 }
1194
1201 template<typename Hi, typename Low>
1202 constexpr LargeInteger<Hi, Low>& operator^=(LargeInteger<Hi, Low>& lhs, typename LargeInteger<Hi, Low>::Self rhs) noexcept {
1203 return lhs = lhs ^ rhs;
1204 }
1205
1206 // ---------------------------------------------------------------------------------------------
1207
1214 template<typename Hi, typename Low> [[nodiscard]] constexpr bool operator==(LargeInteger<Hi, Low> lhs, typename LargeInteger<Hi, Low>::Self rhs) noexcept {
1215 return lhs.high == rhs.high && lhs.low == rhs.low;
1216 }
1217
1224 template<typename Hi, typename Low> [[nodiscard]] constexpr bool operator!=(LargeInteger<Hi, Low> lhs, typename LargeInteger<Hi, Low>::Self rhs) noexcept {
1225 return !(lhs == rhs);
1226 }
1227
1234 template<typename Hi, typename Low> [[nodiscard]] constexpr bool operator<(LargeInteger<Hi, Low> lhs, typename LargeInteger<Hi, Low>::Self rhs) noexcept {
1235 return lhs.high < rhs.high || (lhs.high == rhs.high && lhs.low < rhs.low);
1236 }
1237
1244 template<typename Hi, typename Low> [[nodiscard]] constexpr bool operator<=(LargeInteger<Hi, Low> lhs, typename LargeInteger<Hi, Low>::Self rhs) noexcept {
1245 return !(rhs < lhs);
1246 }
1247
1254 template<typename Hi, typename Low> [[nodiscard]] constexpr bool operator>(LargeInteger<Hi, Low> lhs, typename LargeInteger<Hi, Low>::Self rhs) noexcept {
1255 return rhs < lhs;
1256 }
1257
1264 template<typename Hi, typename Low> [[nodiscard]] constexpr bool operator>=(LargeInteger<Hi, Low> lhs, typename LargeInteger<Hi, Low>::Self rhs) noexcept {
1265 return !(lhs < rhs);
1266 }
1267
1268#if defined(CE_LARGE_INTEGER_HAS_INT128)
1273 [[nodiscard]] constexpr bool operator==(Int128 lhs, Int128 rhs) noexcept {
1274 using Native = __int128;
1275 return static_cast<Native>(lhs) == static_cast<Native>(rhs);
1276 }
1277
1282 [[nodiscard]] constexpr bool operator==(UInt128 lhs, UInt128 rhs) noexcept {
1283 using Native = unsigned __int128;
1284 return static_cast<Native>(lhs) == static_cast<Native>(rhs);
1285 }
1286
1291 [[nodiscard]] constexpr bool operator!=(Int128 lhs, Int128 rhs) noexcept {
1292 using Native = __int128;
1293 return static_cast<Native>(lhs) != static_cast<Native>(rhs);
1294 }
1295
1300 [[nodiscard]] constexpr bool operator!=(UInt128 lhs, UInt128 rhs) noexcept {
1301 using Native = unsigned __int128;
1302 return static_cast<Native>(lhs) != static_cast<Native>(rhs);
1303 }
1304
1309 [[nodiscard]] constexpr bool operator<(Int128 lhs, Int128 rhs) noexcept {
1310 using Native = __int128;
1311 return static_cast<Native>(lhs) < static_cast<Native>(rhs);
1312 }
1313
1318 [[nodiscard]] constexpr bool operator<(UInt128 lhs, UInt128 rhs) noexcept {
1319 using Native = unsigned __int128;
1320 return static_cast<Native>(lhs) < static_cast<Native>(rhs);
1321 }
1322
1327 [[nodiscard]] constexpr bool operator<=(Int128 lhs, Int128 rhs) noexcept {
1328 using Native = __int128;
1329 return static_cast<Native>(lhs) <= static_cast<Native>(rhs);
1330 }
1331
1336 [[nodiscard]] constexpr bool operator<=(UInt128 lhs, UInt128 rhs) noexcept {
1337 using Native = unsigned __int128;
1338 return static_cast<Native>(lhs) <= static_cast<Native>(rhs);
1339 }
1340
1345 [[nodiscard]] constexpr bool operator>(Int128 lhs, Int128 rhs) noexcept {
1346 using Native = __int128;
1347 return static_cast<Native>(lhs) > static_cast<Native>(rhs);
1348 }
1349
1354 [[nodiscard]] constexpr bool operator>(UInt128 lhs, UInt128 rhs) noexcept {
1355 using Native = unsigned __int128;
1356 return static_cast<Native>(lhs) > static_cast<Native>(rhs);
1357 }
1358
1363 [[nodiscard]] constexpr bool operator>=(Int128 lhs, Int128 rhs) noexcept {
1364 using Native = __int128;
1365 return static_cast<Native>(lhs) >= static_cast<Native>(rhs);
1366 }
1367
1372 [[nodiscard]] constexpr bool operator>=(UInt128 lhs, UInt128 rhs) noexcept {
1373 using Native = unsigned __int128;
1374 return static_cast<Native>(lhs) >= static_cast<Native>(rhs);
1375 }
1376#endif
1377
1378 // ---------------------------------------------------------------------------------------------
1379
1385 template<typename Hi, typename Low> [[nodiscard]] constexpr LargeInteger<Hi, Low> abs(LargeInteger<Hi, Low> x) {
1386 if(x.high < Hi(0)) {
1387 return LargeInteger<Hi, Low>(-x.high - (x.low != 0), x.low);
1388 }
1389 return x;
1390 }
1391
1392} // namespace CeresEngine::inline Math
1393
1397template<typename Hi, typename Low> struct std::is_integral<CeresEngine::Math::LargeInteger<Hi, Low>> : std::true_type {};
1398
1402template<typename Hi, typename Low> struct std::is_signed<CeresEngine::Math::LargeInteger<Hi, Low>> : std::is_signed<Hi> {};
1403
1407template<typename Hi, typename Low> struct std::is_unsigned<CeresEngine::Math::LargeInteger<Hi, Low>> : std::is_unsigned<Hi> {};
1408
1412template<typename Hi, typename Low> struct std::make_signed<CeresEngine::Math::LargeInteger<Hi, Low>> {
1413 typedef CeresEngine::Math::LargeInteger<typename std::make_signed<Hi>::type, Low> type;
1414};
1415
1419template<typename Hi, typename Low> struct std::make_unsigned<CeresEngine::Math::LargeInteger<Hi, Low>> {
1420 typedef CeresEngine::Math::LargeInteger<typename std::make_unsigned<Hi>::type, Low> type;
1421};
1422
1423template<typename H, typename L> struct std::hash<CeresEngine::Math::LargeInteger<H, L>> {
1424 using Type = CeresEngine::Math::LargeInteger<H, L>;
1425 constexpr size_t operator()(const Type& obj) const { return CeresEngine::hash(obj.high, obj.low); }
1426};
1427
1432template<typename Hi, typename Low> struct std::numeric_limits<CeresEngine::Math::LargeInteger<Hi, Low>> {
1434 using Tp = CeresEngine::Math::LargeInteger<Hi, Low>;
1435
1437 static inline constexpr bool is_specialized = true;
1438
1440 static inline constexpr bool is_integer = true;
1441
1443 static inline constexpr bool is_signed = numeric_limits<Hi>::is_signed;
1444
1446 static inline constexpr bool is_exact = true;
1447
1450 static inline constexpr bool has_infinity = false;
1451
1454 static inline constexpr bool has_quiet_NaN = false;
1455
1458 static inline constexpr bool has_signaling_NaN = false;
1459
1461 static inline constexpr float_denorm_style has_denorm = denorm_absent;
1462
1465 static inline constexpr bool has_denorm_loss = false;
1466
1468 static inline constexpr float_round_style round_style = round_toward_zero;
1469
1471 static inline constexpr bool is_iec559 = false;
1472
1474 static inline constexpr bool is_bounded = true;
1475
1477 static inline constexpr bool is_modulo = numeric_limits<Hi>::is_modulo;
1478
1480 static inline constexpr int digits = static_cast<int>(sizeof(Tp) * 8 - is_signed);
1481
1483 static inline constexpr int digits10 = digits * 3 / 10;
1484
1487 static inline constexpr int max_digits10 = 0;
1488
1490 static inline constexpr int radix = 2;
1491
1494 static inline constexpr int min_exponent = 0;
1495
1498 static inline constexpr int min_exponent10 = 0;
1499
1502 static inline constexpr int max_exponent = 0;
1503
1506 static inline constexpr int max_exponent10 = 0;
1507
1509 static inline constexpr bool traps = numeric_limits<Hi>::traps;
1510
1512 static inline constexpr bool tinyness_before = false;
1513
1515 [[nodiscard]] static constexpr Tp min() { return is_signed ? Tp(1) << digits : Tp(0); }
1516
1518 [[nodiscard]] static constexpr Tp lowest() { return min(); }
1519
1521 [[nodiscard]] static constexpr Tp max() { return ~min(); }
1522
1525 [[nodiscard]] static constexpr Tp epsilon() { return Tp(0); }
1526
1528 [[nodiscard]] static constexpr Tp round_error() { return Tp(0); }
1529
1531 [[nodiscard]] static constexpr Tp infinity() { return Tp(0); }
1532
1534 [[nodiscard]] static constexpr Tp quiet_NaN() { return Tp(0); }
1535
1537 [[nodiscard]] static constexpr Tp signaling_NaN() { return Tp(0); }
1538
1541 [[nodiscard]] static constexpr Tp denorm_min() { return Tp(0); }
1542};
constexpr size_t hash(const T &v)
Generates a hash for the provided type.
Definition Hash.hpp:25
Definition Angle.hpp:20
constexpr void multwide(T a, T b, T &hi, T &lo)
Definition LargeInteger.hpp:253
constexpr void mult128to256(U N, U M, U &H, U &L)
Definition LargeInteger.hpp:293
constexpr void mult128(T N, T M, T &Ans)
Definition LargeInteger.hpp:288
A wide integer type that uses Hi for the high-order bits in the integer data and Lo for the low-order...
Definition LargeInteger.hpp:53
constexpr LargeInteger(long double value) noexcept
Creates a new LargeInteger by converting from the floating point value.
Definition LargeInteger.hpp:210
constexpr LargeInteger(double value) noexcept
Creates a new LargeInteger by converting from the floating point value.
Definition LargeInteger.hpp:188
constexpr LargeInteger(Tp value) noexcept
Creates a new LargeInteger by converting from the native integer value.
Definition LargeInteger.hpp:109
constexpr LargeInteger() noexcept=default
Creates a new LargeInteger initialized to the value of 0.
constexpr LargeInteger(float value) noexcept
Creates a new LargeInteger by converting from the floating point value.
Definition LargeInteger.hpp:166