@@ -11,14 +11,90 @@ namespace cp_algo::math {
1111 };
1212 template <base_v base = x10>
1313 struct bigint {
14+ static constexpr uint64_t Base = uint64_t (base);
1415 static constexpr uint16_t digit_length = base == x10 ? 16 : 15 ;
1516 static constexpr uint16_t sub_base = base == x10 ? 10 : 16 ;
1617 static constexpr uint32_t meta_base = base == x10 ? uint32_t (1e4 ) : uint32_t (1 << 15 );
1718 big_basic_string<uint64_t > digits;
1819 bool negative;
1920
21+ auto operator <=> (bigint const & other) const {
22+ // Handle zero cases
23+ if (digits.empty () && other.digits .empty ()) {
24+ return std::strong_ordering::equal;
25+ }
26+ if (digits.empty ()) {
27+ return other.negative ? std::strong_ordering::greater : std::strong_ordering::less;
28+ }
29+ if (other.digits .empty ()) {
30+ return negative ? std::strong_ordering::less : std::strong_ordering::greater;
31+ }
32+
33+ // Handle sign differences
34+ if (negative != other.negative ) {
35+ return negative ? std::strong_ordering::less : std::strong_ordering::greater;
36+ }
37+
38+ // Both have the same sign - compare magnitudes
39+ if (digits.size () != other.digits .size ()) {
40+ auto size_cmp = digits.size () <=> other.digits .size ();
41+ // If both negative, reverse the comparison
42+ return negative ? 0 <=> size_cmp : size_cmp;
43+ }
44+
45+ // Same size, compare digits from most significant to least
46+ for (auto i = ssize (digits) - 1 ; i >= 0 ; i--) {
47+ auto digit_cmp = digits[i] <=> other.digits [i];
48+ if (digit_cmp != std::strong_ordering::equal) {
49+ return negative ? 0 <=> digit_cmp : digit_cmp;
50+ }
51+ }
52+
53+ return std::strong_ordering::equal;
54+ }
55+
2056 bigint () {}
2157
58+ bigint (big_basic_string<uint64_t > d, bool neg): digits(std::move(d)), negative(neg) {
59+ normalize ();
60+ }
61+
62+ bigint& pad_inplace (size_t to_add) {
63+ digits.insert (0 , to_add, 0 );
64+ return normalize ();
65+ }
66+ bigint& drop_inplace (size_t to_drop) {
67+ digits.erase (0 , std::min (to_drop, size (digits)));
68+ return normalize ();
69+ }
70+ bigint& take_inplace (size_t to_keep) {
71+ digits.erase (std::min (to_keep, size (digits)), std::string::npos);
72+ return normalize ();
73+ }
74+ bigint& top_inplace (size_t to_keep) {
75+ if (to_keep >= size (digits)) {
76+ return pad_inplace (to_keep - size (digits));
77+ } else {
78+ return drop_inplace (size (digits) - to_keep);
79+ }
80+ }
81+ bigint pad (size_t to_add) const {
82+ return bigint{big_basic_string<uint64_t >(to_add, 0 ) + digits, negative}.normalize ();
83+ }
84+ bigint drop (size_t to_drop) const {
85+ return bigint{digits.substr (std::min (to_drop, size (digits))), negative}.normalize ();
86+ }
87+ bigint take (size_t to_keep) const {
88+ return bigint{digits.substr (0 , std::min (to_keep, size (digits))), negative}.normalize ();
89+ }
90+ bigint top (size_t to_keep) const {
91+ if (to_keep >= size (digits)) {
92+ return pad (to_keep - size (digits));
93+ } else {
94+ return drop (size (digits) - to_keep);
95+ }
96+ }
97+
2298 bigint& normalize () {
2399 while (!empty (digits) && digits.back () == 0 ) {
24100 digits.pop_back ();
@@ -223,43 +299,39 @@ namespace cp_algo::math {
223299 return in;
224300 }
225301
226- template <base_v base>
227- decltype (std::cout)& operator << ( decltype (std::cout) &out, cp_algo::math::bigint<base> const & x ) {
302+ template <base_v base, bool fill = true >
303+ auto & print_digit ( auto &out, uint64_t d ) {
228304 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- }
305+ auto [ptr, ec] = std::to_chars (buf, buf + sizeof (buf), d, bigint<base>::sub_base);
306+ if constexpr (base == x16) {
307+ std::ranges::transform (buf, buf, toupper);
240308 }
309+ auto len = ptr - buf;
310+ if constexpr (fill) {
311+ out << std::string (bigint<base>::digit_length - len, ' 0' );
312+ }
313+ return out << std::string_view (buf, len);
314+ }
315+
316+ template <bool fill_all = false , base_v base>
317+ auto & print_bigint (auto &out, cp_algo::math::bigint<base> const & x) {
241318 if (x.negative ) {
242319 out << ' -' ;
243320 }
244321 if (empty (x.digits )) {
245- return out << ' 0' ;
246- }
247- auto [ptr, ec] = std::to_chars (buf, buf + sizeof (buf), x.digits .back (), bigint<base>::sub_base);
248- if constexpr (base == x16) {
249- std::ranges::transform (buf, buf, toupper);
322+ return print_digit<base, fill_all>(out, 0 );
250323 }
251- out << std::string_view (buf, ptr - buf );
324+ print_digit<base, fill_all>(out, x. digits . back () );
252325 for (auto d: x.digits | std::views::reverse | std::views::drop (1 )) {
253- auto [ptr, ec] = std::to_chars (buf, buf + sizeof (buf), d, bigint<base>::sub_base);
254- if constexpr (base == x16) {
255- std::ranges::transform (buf, buf, toupper);
256- }
257- auto len = ptr - buf;
258- out << std::string (bigint<base>::digit_length - len, ' 0' );
259- out << std::string_view (buf, len);
326+ print_digit<base, true >(out, d);
260327 }
261328 return out;
262329 }
330+
331+ template <base_v base>
332+ decltype (std::cout)& operator << (decltype (std::cout) &out, cp_algo::math::bigint<base> const & x) {
333+ return print_bigint (out, x);
334+ }
263335}
264336
265337#endif // CP_ALGO_MATH_BIGINT_HPP
0 commit comments