HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
int_carry.hpp
1// Copyright Take Vos 2019-2021.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "required.hpp"
8#include "cast.hpp"
9#include <complex>
10#include <cmath>
11#include <limits>
12#include <span>
13#include <tuple>
14#include <concepts>
15
16#if TT_COMPILER == TT_CC_MSVC
17#include <intrin.h>
18#endif
19#if TT_PROCESSOR == TT_CPU_X64
20#include <immintrin.h>
21#endif
22
23namespace tt {
24
31template<typename T> requires (std::unsigned_integral<T>)
32constexpr std::pair<T, T> shift_left_carry(T lhs, unsigned int rhs, T carry = 0) noexcept
33{
34 constexpr unsigned int nr_bits = sizeof(T) * 8;
35 unsigned int reverse_count = nr_bits - rhs;
36
37 return {
38 (lhs << rhs) | carry,
39 lhs >> reverse_count
40 };
41}
42
49template<typename T> requires (std::unsigned_integral<T>)
50constexpr std::pair<T, T> shift_right_carry(T lhs, unsigned int rhs, T carry = 0) noexcept
51{
52 constexpr unsigned int nr_bits = sizeof(T) * 8;
53 unsigned int reverse_count = nr_bits - rhs;
54
55 return {
56 (lhs >> rhs) | carry,
57 lhs << reverse_count
58 };
59}
60
61
66template<typename T> requires (std::unsigned_integral<T>)
67constexpr std::pair<T, T> add_carry(T a, T b, T carry = 0) noexcept
68{
69 if constexpr (sizeof(T) == 1) {
70 uint16_t r = static_cast<uint16_t>(a) + static_cast<uint16_t>(b) + carry;
71 return { static_cast<uint8_t>(r), static_cast<uint8_t>(r >> 8) };
72
73 } else if constexpr (sizeof(T) == 2) {
74 uint32_t r = static_cast<uint32_t>(a) + static_cast<uint32_t>(b) + carry;
75 return { static_cast<uint16_t>(r), static_cast<uint16_t>(r >> 16) };
76
77 } else if constexpr (sizeof(T) == 4) {
78 uint64_t r = static_cast<uint64_t>(a) + static_cast<uint64_t>(b) + carry;
79 return { static_cast<uint32_t>(r), static_cast<uint32_t>(r >> 32) };
80
81 } else if constexpr (sizeof(T) == 8) {
82#if TT_COMPILER == TT_CC_CLANG || TT_COMPILER == TT_CC_GCC
83 auto r = static_cast<__uint128_t>(a) + static_cast<__uint128_t>(b) + carry;
84 return { static_cast<uint64_t>(r), static_cast<uint64_t>(r >> 64) };
85#else
86 uint64_t r1 = a + b;
87 uint64_t c = (r1 < a) ? 1 : 0;
88 uint64_t r2 = r1 + carry;
89 c += (r2 < r1) ? 1 : 0;
90 return { r2, c };
91#endif
92 }
93}
94
95template<typename T> requires (std::unsigned_integral<T>)
96constexpr std::pair<T, T> wide_multiply(T a, T b) noexcept
97{
98 if constexpr (sizeof(T) == 1) {
99 uint16_t r = static_cast<uint16_t>(a) * static_cast<uint16_t>(b);
100 return { static_cast<uint8_t>(r), static_cast<uint8_t>(r >> 8) };
101
102 } else if constexpr (sizeof(T) == 2) {
103 uint32_t r = static_cast<uint32_t>(a) * static_cast<uint32_t>(b);
104 return { static_cast<uint16_t>(r), static_cast<uint16_t>(r >> 16) };
105
106 } else if constexpr (sizeof(T) == 4) {
107 uint64_t r = static_cast<uint64_t>(a) * static_cast<uint64_t>(b);
108 return { static_cast<uint32_t>(r), static_cast<uint32_t>(r >> 32) };
109
110 } else if constexpr (sizeof(T) == 8) {
111#if TT_COMPILER == TT_CC_MSVC
112 uint64_t hi = 0;
113 uint64_t lo = _umul128(a, b, &hi);
114 return { lo, hi };
115
116#elif TT_COMPILER == TT_CC_CLANG || TT_COMPILER == TT_CC_GCC
117 auto r = static_cast<__uint128_t>(a) * static_cast<__uint128_t>(b);
118 return { static_cast<uint64_t>(r), static_cast<uint64_t>(r >> 64) };
119#else
120#error "Not implemented"
121#endif
122 }
123}
124
125template<typename T> requires (std::unsigned_integral<T>)
126constexpr std::pair<T, T> multiply_carry(T a, T b, T carry = 0, T accumulator = 0) noexcept
127{
128 if constexpr (sizeof(T) == 1) {
129 uint16_t r = static_cast<uint16_t>(a) * static_cast<uint16_t>(b) + carry + accumulator;
130 return { static_cast<uint8_t>(r), static_cast<uint8_t>(r >> 8) };
131
132 } else if constexpr (sizeof(T) == 2) {
133 uint32_t r = static_cast<uint32_t>(a) * static_cast<uint32_t>(b) + carry + accumulator;
134 return { static_cast<uint16_t>(r), static_cast<uint16_t>(r >> 16) };
135
136 } else if constexpr (sizeof(T) == 4) {
137 uint64_t r = static_cast<uint64_t>(a) * static_cast<uint64_t>(b) + carry + accumulator;
138 return { static_cast<uint32_t>(r), static_cast<uint32_t>(r >> 32) };
139
140 } else if constexpr (sizeof(T) == 8) {
141#if TT_COMPILER == TT_CC_MSVC
142 uint64_t hi = 0;
143 uint64_t lo = _umul128(a, b, &hi);
144 uint64_t c = 0;
145 std::tie(lo, c) = add_carry(lo, carry, uint64_t{0});
146 std::tie(hi, c) = add_carry(hi, uint64_t{0}, c);
147 std::tie(lo, c) = add_carry(lo, accumulator, uint64_t{0});
148 std::tie(hi, c) = add_carry(hi, uint64_t{0}, c);
149 return { lo, hi };
150
151#elif TT_COMPILER == TT_CC_CLANG || TT_COMPILER == TT_CC_GCC
152 auto r = static_cast<__uint128_t>(a) * static_cast<__uint128_t>(b) + carry + accumulator;
153 return { static_cast<uint64_t>(r), static_cast<uint64_t>(r >> 64) };
154#else
155#error "Not implemented"
156#endif
157 }
158}
159
160}
T tie(T... args)