Skip to content

Commit 6fd3be2

Browse files
menggabungkan implementasi big_int dalam header itu sendiri
ternyata lebih mudah disatukan, bacanya enak di sisi editor(vim)
1 parent 579a53c commit 6fd3be2

File tree

4 files changed

+269
-308
lines changed

4 files changed

+269
-308
lines changed

number_system/CMakeLists.txt

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@ add_test(NAME "Test suffix prime class and print as Test, is prime" COMMAND prim
1616
add_test(NAME "Test find and print 100 fibonacci " COMMAND fibonacci -l 100)
1717
add_test(NAME "Test find and print 100th fibonnaci" COMMAND fibonacci -i 100)
1818

19-
#library
20-
add_library(big_int SHARED ${SRC_SOURCES}/big_int.cxx)
21-
#add_library(big_int STATIC ${SRC_SOURCES}/big_int.cxx)
22-
2319
# Untuk Testing
24-
add_executable(big_int_test ${SRC_SOURCES}/big_int.cxx test/big_int.cxx)
20+
add_executable(big_int_test ${SRC_SOURCES}/big_int.cxx)
2521
#add_test(NAME "Test big_int" COMMAND big_int_test)

number_system/include/big_int.hxx

Lines changed: 252 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,107 @@
11
#pragma once
2+
#include <cassert>
23
#include <cstdint>
34
#include <iostream>
45
#include <string>
56
#include <vector>
67

7-
std::string uint64_t_to_string(uint64_t val);
8-
uint64_t string_to_uint64_t(const std::string &val);
9-
void mul_2_64_add_other(std::string &val, uint64_t other);
10-
void div_mod_2_64(const std::string &val, std::string *rem);
11-
12-
#define __BIGINT_OPERATOR_DECL(op, alter) \
13-
big_int alter(const big_int &other) const; \
14-
big_int operator op(const big_int &other) const { return alter(other); }
15-
#define __BIGINT_OPERATOR_LOGIC_DECL(op, alter) \
16-
bool alter(const big_int &other) const; \
17-
bool operator op(const big_int &other) const { return alter(other); }
18-
19-
#define __BIGINT_OPERATOR_SHIFT_DECL(type) \
20-
big_int shift_left(type other) const; \
21-
big_int operator<<(type other) const { return shift_left(other); } \
22-
big_int shift_right(type other) const; \
23-
big_int operator>>(type other) const { return shift_right(other); }
24-
258
// most 64bit on the highest index
269
class big_int {
2710
private:
2811
std::vector<uint64_t> values;
29-
std::string values_str;
12+
// mutable = non logic state
13+
mutable std::string values_str;
3014
bool negative = false;
3115
const static uint16_t max_thread;
3216

3317
// For positive only
3418
big_int(std::vector<uint64_t> values) : values(values) {}
19+
std::string uint64_to_string(uint64_t val) {
20+
std::string res;
21+
if (!val) return "0";
22+
while (val) {
23+
res.insert(res.begin(), val % 10 + '0');
24+
val /= 10;
25+
}
26+
return res;
27+
}
28+
29+
uint64_t string_to_uint64_t(const std::string &val) {
30+
uint64_t res = 0;
31+
for (auto c : val) res = res * 10 + c - '0';
32+
return res;
33+
}
34+
35+
void mul_2_64_add_other(std::string &val, uint64_t other) {
36+
using namespace std;
37+
if (val.empty() || val == "0") {
38+
val = uint64_to_string(other);
39+
return;
40+
}
41+
std::string res;
42+
// multiply
43+
std::vector<int> tmpres(val.size() + big_int::two_pow_64.size(), 0);
44+
for (size_t i = 0; i < val.size(); ++i) {
45+
size_t rev_i = val.size() - 1 - i;
46+
for (size_t j = 0; j < big_int::two_pow_64.size(); ++j) {
47+
size_t rev_j = big_int::two_pow_64.size() - 1 - j;
48+
int mul = (val[rev_i] - '0') * (big_int::two_pow_64[rev_j] - '0');
49+
size_t p1 = rev_i + rev_j, p2 = p1 + 1;
50+
int sum = tmpres[p2] + mul;
51+
tmpres[p2] = sum % 10;
52+
tmpres[p1] += sum / 10;
53+
}
54+
}
55+
56+
if (!other) return;
57+
58+
// add the other
59+
std::string b = uint64_to_string(other);
60+
int carry = 0;
61+
62+
for (size_t i = 0; i < b.size(); ++i) {
63+
size_t rev_i = tmpres.size() - 1 - i;
64+
size_t rev_i_b = b.size() - 1 - i;
65+
int sum = b[rev_i_b] - '0' + tmpres[rev_i];
66+
sum += carry;
67+
carry = sum / 10;
68+
tmpres[rev_i] = sum % 10;
69+
}
70+
71+
for (int i = 0; carry && i < tmpres.size(); ++i) {
72+
int sum = tmpres[tmpres.size() - i - 1] + carry;
73+
tmpres[tmpres.size() - i - 1] = sum % 10;
74+
carry = sum / 10;
75+
}
76+
77+
if (carry) tmpres.insert(tmpres.begin(), 1, carry);
78+
79+
while (!tmpres[0]) tmpres.erase(tmpres.begin());
80+
res.resize(tmpres.size());
81+
for (size_t i = 0; i < tmpres.size(); ++i) res[i] = tmpres[i] + '0';
82+
83+
val = res;
84+
}
85+
86+
// TODO : Implement this method
87+
void div_mod_2_64(std::string &val, std::string *remainder) const {
88+
if (val.size() < big_int::two_pow_64.size()) {
89+
if (remainder) *remainder = val;
90+
val = "";
91+
return;
92+
}
93+
std::vector<int> sub_res(val.size(), 0);
94+
size_t offset = val.size() - big_int::two_pow_64.size();
95+
uint64_t div_res = 0;
96+
bool greater_equal = true;
97+
bool carry = 0;
98+
while (greater_equal) {
99+
for (size_t i = 0; i < val.size(); ++i) {
100+
size_t rev_val_i = val.size() - 1 - i;
101+
size_t rev_2_64_i = rev_val_i - offset;
102+
}
103+
}
104+
}
35105

36106
public:
37107
// done
@@ -40,51 +110,180 @@ class big_int {
40110
: values(values), negative(negative) {}
41111

42112
big_int(uint64_t value) {
43-
if (value < (1ULL << 63))
44-
values = {value};
113+
if (value < (1ULL << 63)) values = {value};
45114
else {
46115
values = {~value + 1};
47116
this->negative = true;
48117
}
49118
}
50119

51-
big_int(const std::string &value);
120+
big_int(std::string value) {
121+
std::string rem = "0";
122+
std::vector<uint64_t> chunks;
123+
while (!value.empty()) {
124+
div_mod_2_64(value, &rem);
125+
chunks.push_back(string_to_uint64_t(rem));
126+
}
127+
}
128+
129+
std::string to_string() const {}
130+
131+
#define FUNC_OP(op) big_int op(const big_int &other) const
52132

53-
// c/cpp aneh banget, perlu const di belakang untuk menandakan fungsi tidak
54-
// merubah big_int
55-
std::string to_string() const;
133+
FUNC_OP(add) {
134+
std::vector<uint64_t> this_copy = this->values, other_copy = other.values,
135+
result;
56136

57-
static const big_int ONE;
137+
// for flag and result
138+
bool negative = false;
58139

59-
__BIGINT_OPERATOR_DECL(+, add);
60-
__BIGINT_OPERATOR_DECL(-, min);
61-
__BIGINT_OPERATOR_DECL(*, mul);
62-
__BIGINT_OPERATOR_DECL(/, div);
140+
// padding
141+
if (this->values.size() != other.values.size()) {
142+
size_t pad = this->values.size() > other.values.size()
143+
? this->values.size() - other.values.size()
144+
: other.values.size() - this->values.size();
145+
this->values.size() > other.values.size()
146+
? other_copy.insert(other_copy.begin(), pad, 0)
147+
: this_copy.insert(this_copy.begin(), pad, 0);
148+
}
63149

150+
// inverse bit and add 1 for negative
151+
if (this->negative != other.negative) {
152+
negative = true;
153+
bool carry = 1;
154+
if (this->negative) {
155+
for (size_t i = 0; i < this_copy.size(); ++i) {
156+
this_copy[i] = ~this_copy[i] + carry;
157+
carry = this_copy[i] == 0;
158+
}
159+
} else {
160+
for (size_t i = 0; i < this_copy.size(); ++i) {
161+
other_copy[i] = ~other_copy[i] + carry;
162+
carry = other_copy[i] == 0;
163+
}
164+
}
165+
}
166+
167+
bool carry = false;
168+
for (size_t i = 0; i < this_copy.size(); ++i) {
169+
result.push_back(this_copy[i] + other_copy[i] + carry);
170+
carry =
171+
(result[i] < this_copy[i] || (carry && result[i] == this_copy[i]));
172+
}
173+
174+
// if carry (outside to make sure if false skip) but both not equal
175+
// negative=false, if not add the carry
176+
if (carry) {
177+
if (negative) negative = false;
178+
else {
179+
result.push_back(1);
180+
if (this->negative) negative = true;
181+
}
182+
}
183+
184+
return big_int(result, negative);
185+
}
186+
187+
FUNC_OP(min) {
188+
big_int big_new(other.values, !other.negative);
189+
return this->add(big_new);
190+
}
191+
FUNC_OP(mul) {
192+
size_t res_bit = (this->values.size() << 6) + (other.values.size() << 6);
193+
if (res_bit < this->values.size())
194+
throw std::runtime_error("overflow reached");
195+
196+
big_int res(0);
197+
198+
if (this->negative ^ other.negative) res.negative = true;
199+
200+
for (size_t i = 0; i < other.values.size(); ++i) {
201+
uint64_t factor = other.values[i];
202+
for (uint8_t j = 1; j < uint8_t(1 << 6); ++j) {
203+
if (factor & (1ULL << j)) res = res + (*this << j);
204+
factor = factor >> 1;
205+
}
206+
}
207+
return res;
208+
}
209+
210+
FUNC_OP(div) {}
211+
#undef FUNC_OP
212+
213+
#define OPERATOR_DECL(op, alter) \
214+
big_int operator op(const big_int &other) const { return alter(other); }
215+
OPERATOR_DECL(+, add);
216+
OPERATOR_DECL(-, min);
217+
OPERATOR_DECL(*, mul);
218+
OPERATOR_DECL(/, div);
219+
#undef OPERATOR_DECL
64220
// special case
65-
big_int operator++(int) { return add(ONE); }
66-
big_int operator--(int) { return min(ONE); }
67-
bool operator!() { return values_str.empty() || values_str == "0"; }
68-
69-
__BIGINT_OPERATOR_DECL(&, _and)
70-
__BIGINT_OPERATOR_DECL(|, _or)
71-
__BIGINT_OPERATOR_DECL(^, _xor)
72-
73-
__BIGINT_OPERATOR_LOGIC_DECL(>, gt);
74-
__BIGINT_OPERATOR_LOGIC_DECL(>=, gteq);
75-
__BIGINT_OPERATOR_LOGIC_DECL(<, lt);
76-
__BIGINT_OPERATOR_LOGIC_DECL(<=, lteq);
77-
__BIGINT_OPERATOR_LOGIC_DECL(==, equal);
78-
__BIGINT_OPERATOR_LOGIC_DECL(!=, noteq);
79-
__BIGINT_OPERATOR_LOGIC_DECL(&&, andand);
80-
__BIGINT_OPERATOR_LOGIC_DECL(||, oror);
81-
82-
// uint64_t udah cukup, terlanjur bikin makronya males ngapus
83-
__BIGINT_OPERATOR_SHIFT_DECL(size_t);
84-
#undef __BIGINT_OPERATOR_DECL
85-
#undef __BIGINT_OPERATOR_LOGIC_DECL
86-
#undef __BIGINT_OPERATOR_SHIFT_DECL
87-
};
221+
big_int operator++(int) { return add(big_int(1)); }
222+
big_int operator--(int) { return min(big_int(1)); }
223+
bool operator!() {
224+
return (values.size() == 1 && values[0] == 0) || values.empty();
225+
}
226+
227+
#define BITWISE(op) big_int operator op(const big_int &other) const
228+
229+
BITWISE(&) {}
230+
#undef BITWISE
231+
232+
#define OPERATOR_LOGIC_DECL(op, alter) \
233+
bool alter(const big_int &other) const; \
234+
bool operator op(const big_int &other) const { return alter(other); }
235+
236+
OPERATOR_LOGIC_DECL(>, gt);
237+
OPERATOR_LOGIC_DECL(>=, gteq);
238+
OPERATOR_LOGIC_DECL(<, lt);
239+
OPERATOR_LOGIC_DECL(<=, lteq);
240+
OPERATOR_LOGIC_DECL(==, equal);
241+
OPERATOR_LOGIC_DECL(!=, noteq);
242+
OPERATOR_LOGIC_DECL(&&, andand);
243+
OPERATOR_LOGIC_DECL(||, oror);
244+
245+
big_int shift_left(uint64_t k) const {
246+
std::vector<uint64_t> res_values(this->values);
247+
if (!k) return big_int(res_values, this->negative);
248+
assert((k >> 6) + res_values.size() > res_values.size());
249+
if (k >> 6) res_values.insert(res_values.end(), k >> 6, 0);
250+
uint64_t carry = 0;
251+
uint64_t bits = (k & 63ULL);
252+
// mencegah shifting 64 kali jika k kelipatan 64 karena 64-0 dilewatkan
253+
if (bits) {
254+
for (auto it = res_values.rbegin(); it != res_values.rend(); ++it) {
255+
uint64_t tmp = *it << bits | carry;
256+
carry = *it >> (64ULL - bits);
257+
*it = tmp;
258+
}
259+
}
260+
return big_int(res_values, this->negative);
261+
}
262+
263+
big_int operator<<(uint64_t k) const { return shift_left(k); }
264+
265+
big_int shift_right(uint64_t k) const {
266+
std::vector<uint64_t> res_values(this->values);
267+
if (!k) return big_int(res_values, this->negative);
268+
if (k >> 6 >= res_values.size()) return big_int({0}, this->negative);
269+
if (k >> 6) res_values.resize(res_values.size() - (k >> 6));
270+
uint64_t carry = 0;
271+
uint64_t bits = (k & 63ULL);
272+
if (bits) {
273+
for (auto it = res_values.begin(); it != res_values.end(); ++it) {
274+
uint64_t tmp = *it >> bits | carry;
275+
carry = *it << (64ULL - bits);
276+
*it = tmp;
277+
}
278+
}
279+
while (res_values.size() > 1 && !res_values.back()) res_values.pop_back();
280+
return big_int(res_values, this->negative);
281+
}
282+
283+
big_int operator>>(uint64_t k) const { return shift_right(k); }
284+
}; // END big_int class
285+
// static member init
286+
const std::string two_pow_64 = "18446744073709551616";
88287

89288
inline big_int operator""_big(unsigned long long i) { return big_int(i); }
90289
inline big_int operator""_big(const char *str, size_t size) {

0 commit comments

Comments
 (0)