Skip to content

Commit 6cfb439

Browse files
committed
Improve tiny integers case
1 parent 4df6a31 commit 6cfb439

File tree

3 files changed

+68
-20
lines changed

3 files changed

+68
-20
lines changed

cp-algo/math/bigint.hpp

Lines changed: 60 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ namespace cp_algo::math {
1414
static constexpr uint16_t digit_length = base == x10 ? 16 : 15;
1515
static constexpr uint16_t sub_base = base == x10 ? 10 : 16;
1616
static constexpr uint32_t meta_base = base == x10 ? uint32_t(1e4) : uint32_t(1 << 15);
17-
big_vector<uint64_t> digits;
17+
big_basic_string<uint64_t> digits;
1818
bool negative;
1919

2020
bigint() {}
@@ -95,8 +95,18 @@ namespace cp_algo::math {
9595
}
9696
return *this;
9797
}
98-
98+
bigint(int64_t x) {
99+
negative = x < 0;
100+
x = negative ? -x : x;
101+
digits = x ? big_basic_string<uint64_t>{uint64_t(x)} : big_basic_string<uint64_t>{};
102+
}
99103
bigint(std::span<char> s): negative(false) {
104+
if (size(s) < digit_length) {
105+
int64_t val = 0;
106+
std::from_chars(s.data(), s.data() + size(s), val, sub_base);
107+
*this = bigint(val);
108+
return;
109+
}
100110
if (!empty(s) && s[0] == '-') {
101111
negative = true;
102112
s = s.subspan(1);
@@ -153,25 +163,43 @@ namespace cp_algo::math {
153163
carry /= base;
154164
}
155165
}
166+
bigint& operator *= (int64_t other) {
167+
if (other < 0) {
168+
negative ^= 1;
169+
other = -other;
170+
}
171+
if (other == 0) {
172+
return *this = bigint(0);
173+
} else if (other == 1) {
174+
return *this;
175+
}
176+
uint64_t carry = 0;
177+
for (auto &d: digits) {
178+
__uint128_t val = __uint128_t(d) * other + carry;
179+
d = uint64_t(val % base);
180+
carry = uint64_t(val / base);
181+
}
182+
if (carry) {
183+
digits.push_back(carry % base);
184+
carry /= base;
185+
}
186+
return *this;
187+
}
188+
bigint operator * (int64_t other) const {
189+
return bigint(*this) *= other;
190+
}
191+
friend bigint operator * (int64_t lhs, const bigint& rhs) {
192+
return bigint(rhs) *= lhs;
193+
}
156194
bigint& mul_inplace(auto &&other) {
157-
size_t n = size(digits);
158-
size_t m = size(other.digits);
159195
negative ^= other.negative;
160-
if (std::min(n, m) < 128) {
161-
big_vector<uint64_t> result(n + m);
162-
for (size_t i = 0; i < n; i++) {
163-
uint64_t carry = 0;
164-
for (size_t j = 0; j < m || carry; j++) {
165-
__uint128_t cur = result[i + j] + carry;
166-
if (j < m) {
167-
cur += __uint128_t(digits[i]) * other.digits[j];
168-
}
169-
result[i + j] = uint64_t(cur % base);
170-
carry = uint64_t(cur / base);
171-
}
172-
}
173-
digits = std::move(result);
174-
return normalize();
196+
auto n = size(digits), m = size(other.digits);
197+
if (n < m) {
198+
std::swap(n, m);
199+
std::swap(digits, other.digits);
200+
}
201+
if (m <= 1) {
202+
return *this *= int64_t(m == 0 ? 0 : other.digits[0]);
175203
}
176204
to_metabase();
177205
other.to_metabase();
@@ -197,13 +225,25 @@ namespace cp_algo::math {
197225

198226
template<base_v base>
199227
decltype(std::cout)& operator << (decltype(std::cout) &out, cp_algo::math::bigint<base> const& x) {
228+
char buf[16];
229+
if (size(x.digits) <= 1) {
230+
if (x.negative) {
231+
out << '-';
232+
}
233+
if constexpr (base == x16) {
234+
auto [ptr, ec] = std::to_chars(buf, buf + sizeof(buf), empty(x.digits) ? 0 : x.digits[0], bigint<base>::sub_base);
235+
std::ranges::transform(buf, buf, toupper);
236+
return out << std::string_view(buf, ptr - buf);
237+
} else {
238+
return out << (empty(x.digits) ? 0 : x.digits[0]);
239+
}
240+
}
200241
if (x.negative) {
201242
out << '-';
202243
}
203244
if (empty(x.digits)) {
204245
return out << '0';
205246
}
206-
char buf[20];
207247
auto [ptr, ec] = std::to_chars(buf, buf + sizeof(buf), x.digits.back(), bigint<base>::sub_base);
208248
if constexpr (base == x16) {
209249
std::ranges::transform(buf, buf, toupper);

cp-algo/math/fft64.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,10 @@ namespace cp_algo::math::fft {
120120

121121
void conv64(auto& a, auto const& b) {
122122
size_t n = a.size(), m = b.size();
123+
if (n == 0 || m == 0) {
124+
a.clear();
125+
return;
126+
}
123127
size_t N = std::max(flen, std::bit_ceil(n + m - 1) / 2);
124128
dft64 A(a, N), B(b, N);
125129
A.dot(B);

cp-algo/math/fft_simple.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ namespace cp_algo::math::fft {
3636

3737
// Multiplies a and b, assuming perfect precision and no overflow
3838
void conv_simple(auto& a, auto const& b) {
39+
if (empty(a) || empty(b)) {
40+
a.clear();
41+
return;
42+
}
3943
size_t n = a.size(), m = b.size();
4044
size_t N = std::max(flen, std::bit_ceil(n + m - 1) / 2);
4145
dft_simple A(a, N), B(b, N);

0 commit comments

Comments
 (0)