diff --git a/src/include/int.hpp b/src/include/int.hpp new file mode 100644 index 0000000..32ca7e3 --- /dev/null +++ b/src/include/int.hpp @@ -0,0 +1,425 @@ +#include +#include +#include + +/** + * @brief Options for `base` parameter used in GMP's `mpz_set_str` and + * `mpz_sizeinbase`. + * @see https://gmplib.org/manual/Assigning-Integers + * + * `base_N`: no characters, no case sensitivity. + * `ci_N`: case-insensitive (`A`=`10`, `a`=`10`) + * `cs_N`: case-sensitive (`A`=`10`, `a`=`36`) + */ +enum class base { + base_2 = 2, + base_3 = 3, + base_4 = 4, + base_5 = 5, + base_6 = 6, + base_7 = 7, + base_8 = 8, + base_9 = 9, + ci_10 = 10, + ci_11 = 11, + ci_12 = 12, + ci_13 = 13, + ci_14 = 14, + ci_15 = 15, + ci_16 = 16, + ci_17 = 17, + ci_18 = 18, + ci_19 = 19, + ci_20 = 20, + ci_21 = 21, + ci_22 = 22, + ci_23 = 23, + ci_24 = 24, + ci_25 = 25, + ci_26 = 26, + ci_27 = 27, + ci_28 = 28, + ci_29 = 29, + ci_30 = 30, + ci_31 = 31, + ci_32 = 32, + ci_33 = 33, + ci_34 = 34, + ci_35 = 35, + ci_36 = 36, + cs_37 = 37, + cs_38 = 38, + cs_39 = 39, + cs_40 = 40, + cs_41 = 41, + cs_42 = 42, + cs_43 = 43, + cs_44 = 44, + cs_45 = 45, + cs_46 = 46, + cs_47 = 47, + cs_48 = 48, + cs_49 = 49, + cs_50 = 50, + cs_51 = 51, + cs_52 = 52, + cs_53 = 53, + cs_54 = 54, + cs_55 = 55, + cs_56 = 56, + cs_57 = 57, + cs_58 = 58, + cs_59 = 59, + cs_60 = 60, + cs_61 = 61, + cs_62 = 62, + binary = base_2, + octal = base_8, + decimal = ci_10, + hexadecimal = ci_16, +}; + +/** + * @brief Options for `base` parameter used in GMP's `mpz_get_str`. + * @see https://gmplib.org/manual/Converting-Integers + * + * `base_N`: case sensitive. It doesn't have its upper and lower case versions. + * + * `lc_N`: lower-case, base N. All letters are lower case. + * + * `uc_N`: upper-case, base N. All letters are upper case. + */ +enum class print_base { + lc_2 = 2, + lc_3 = 3, + lc_4 = 4, + lc_5 = 5, + lc_6 = 6, + lc_7 = 7, + lc_8 = 8, + lc_9 = 9, + lc_10 = 10, + lc_11 = 11, + lc_12 = 12, + lc_13 = 13, + lc_14 = 14, + lc_15 = 15, + lc_16 = 16, + lc_17 = 17, + lc_18 = 18, + lc_19 = 19, + lc_20 = 20, + lc_21 = 21, + lc_22 = 22, + lc_23 = 23, + lc_24 = 24, + lc_25 = 25, + lc_26 = 26, + lc_27 = 27, + lc_28 = 28, + lc_29 = 29, + lc_30 = 30, + lc_31 = 31, + lc_32 = 32, + lc_33 = 33, + lc_34 = 34, + lc_35 = 35, + lc_36 = 36, + uc_2 = -2, + uc_3 = -3, + uc_4 = -4, + uc_5 = -5, + uc_6 = -6, + uc_7 = -7, + uc_8 = -8, + uc_9 = -9, + uc_10 = -10, + uc_11 = -11, + uc_12 = -12, + uc_13 = -13, + uc_14 = -14, + uc_15 = -15, + uc_16 = -16, + uc_17 = -17, + uc_18 = -18, + uc_19 = -19, + uc_20 = -20, + uc_21 = -21, + uc_22 = -22, + uc_23 = -23, + uc_24 = -24, + uc_25 = -25, + uc_26 = -26, + uc_27 = -27, + uc_28 = -28, + uc_29 = -29, + uc_30 = -30, + uc_31 = -31, + uc_32 = -32, + uc_33 = -33, + uc_34 = -34, + uc_35 = -35, + uc_36 = -36, + base_37 = 37, + base_38 = 38, + base_39 = 39, + base_40 = 40, + base_41 = 41, + base_42 = 42, + base_43 = 43, + base_44 = 44, + base_45 = 45, + base_46 = 46, + base_47 = 47, + base_48 = 48, + base_49 = 49, + base_50 = 50, + base_51 = 51, + base_52 = 52, + base_53 = 53, + base_54 = 54, + base_55 = 55, + base_56 = 56, + base_57 = 57, + base_58 = 58, + base_59 = 59, + base_60 = 60, + base_61 = 61, + base_62 = 62, + octal_lower_case = lc_8, + hex_lower_case = lc_16, + decimal = lc_10, + binary = lc_2, + octal_upper_case = uc_8, + hex_upper_case = uc_16, +}; + +base print_base_to_base(print_base); + +/** + * @brief is an high-performance, arbitrary precision Integer class for mash + */ +class Int { +private: + mpz_t inner; + +public: + Int(); + Int(const Int &); + Int(unsigned long); + Int(long); + Int(double); + Int(const std::string &, base); + + unsigned long to_ul(); + long to_l(); + double to_d(); + std::string to_string(print_base); + + void swap(Int &); + void operator+(const Int &); + void operator+(unsigned long); + void operator+(long); + + void operator-(const Int &); + void operator-(unsigned long); + void operator-(long); + + void operator*(const Int &); + void operator*(unsigned long); + void operator*(long); + + void operator/(const Int &); + void operator/(unsigned long); + void operator/(long); + + void operator%(const Int &); + void operator%(unsigned long); + + void add_mul(Int &); + void add_mul(unsigned long); + void add_mul(long); + + void sub_mul(Int &); + void sub_mul(unsigned long); + void sub_mul(long); + + void mul_2exp(unsigned long); + + void operator~(); + + void abs(); + + void ceil_div_quotient(Int &); + void ceil_div_remainder(Int &); + void ceil_div_both(Int &); + void ceil_div(unsigned long); + void ceil_div_both(unsigned long); + void ceil_div_quotient(unsigned long); + void ceil_div_remainder(unsigned long); + void ceil_div(long); + void ceil_div_both(long); + void ceil_div_quotient(long); + void ceil_div_remainder(long); + void ceil_div_quotient_2exp(unsigned long); + void ceil_div_remainder_2exp(unsigned long); + + void floor_div_quotient(Int &); + void floor_div_remainder(Int &); + void floor_div_both(Int &); + void floor_div(unsigned long); + void floor_div_both(unsigned long); + void floor_div_quotient(unsigned long); + void floor_div_remainder(unsigned long); + void floor_div(long); + void floor_div_both(long); + void floor_div_quotient(long); + void floor_div_remainder(long); + void floor_div_quotient_2exp(unsigned long); + void floor_div_remainder_2exp(unsigned long); + + void truncate_div_quotient(Int &); + void truncate_div_remainder(Int &); + void truncate_div_both(Int &); + void truncate_div(unsigned long); + void truncate_div_both(unsigned long); + void truncate_div_quotient(unsigned long); + void truncate_div_remainder(unsigned long); + void truncate_div(long); + void truncate_div_both(long); + void truncate_div_quotient(long); + void truncate_div_remainder(long); + void truncate_div_quotient_2exp(unsigned long); + void truncate_div_remainder_2exp(unsigned long); + + void mod(Int &); + void mod(unsigned long); + void mod(long); + + void div_exact(Int &); + void div_exact(unsigned long); + void div_exact(long); + + int divisible(Int &); + int divisible(unsigned long); + int divisible(long); + int divisible_2exp(unsigned long); + + int congruent(Int &); + int congruent(unsigned long); + int congruent(long); + int congruent_2exp(unsigned long); + + void mod_pow(Int &); + void mod_pow(unsigned long); + void mod_pow(long); + + void powm_sec(Int &); + + void pow(Int &); + void pow(unsigned long, unsigned long); + void pow(long, unsigned long); + + ~Int() { mpz_clear(inner); }; +}; + +/* +/// +/// Enum for the number's sign. +/// +/// `Zero` is for when number is zero. +/// +pub const Sign = enum(i8) { + Negative = -1, + Positive = 1, + Zero = 0, + + pub fn toChar(self: @This()) u8 { + return switch (self) { + .Negative => '-', + .Positive => '+', + .Zero => '0', + }; + } + + pub fn toString(self: @This()) []const u8 { + return switch (self) { + .Negative => "negative", + .Positive => "positive", + .Zero => "zero", + }; + } +}; + +/// +/// Enum for the comparison of two numbers. +/// +pub const Ordering = enum(i8) { + Less = -1, + Greater = 1, + Equals = 0, + + const Self = @This(); + + pub fn toChar(self: Self) u8 { + return switch (self) { + .Less => '<', + .Greater => '>', + .Equals => '=', + }; + } + + pub fn toString(self: Self) []const u8 { + return switch (self) { + .Less => "less", + .Greater => "greater", + .Equals => "equals", + }; + } + + pub fn fromC(num: c_int) Self { + if (num < 0) return .Less; + if (num > 0) return .Greater; + return .Equals; + } +}; + +/// Enum for the number's parity. +pub const Parity = enum(i8) { + Even = 0, + Odd = 1, + + pub fn toString(self: @This()) []const u8 { + return switch (self) { + .Even => "even", + .Odd => "odd", + }; + } +}; + +//// +/// Rounding methods for division. +/// +/// `Truncate` rounds the integer towards 0. +/// `Ceil` rounds the integer towards positive infinity. +/// `Floor` rounds the integer towrds positiv infinity. +/// +/// |`Number`|`Truncate`|`Ceil`|`Floor`| +/// |--------|----------|------|-------| +/// |`4.5` |`4` |`5` |`4` | +/// |`-4.5` |`-4` |`-4` |`-5` | +/// +pub const RoundingMethod = enum(i8) { + Truncate = 0, + Ceil = 1, + Floor = -1, +}; + +/// +/// Option for which result will be written to the integer. +/// +pub const Output = enum(i8) { + Quotient = 0, + Remainder = 1, +}; +*/ \ No newline at end of file diff --git a/src/int.cpp b/src/int.cpp new file mode 100644 index 0000000..ea2b9d4 --- /dev/null +++ b/src/int.cpp @@ -0,0 +1,342 @@ +#include +#include +#include +#include +#include +#include + +Int::Int() { mpz_init(this->inner); }; +Int::Int(const Int &big) { mpz_init_set(this->inner, big.inner); }; +Int::Int(unsigned long ul) { mpz_init_set_ui(this->inner, ul); }; +Int::Int(long l) { mpz_init_set_si(this->inner, l); }; +Int::Int(double d) { mpz_init_set_d(this->inner, d); }; +Int::Int(const std::string &str, base b) { + int result = mpz_init_set_str(this->inner, str.data(), static_cast(b)); + if (result == 1) + throw std::exception(); +}; + +base print_base_to_base(print_base p_base) { + switch (p_base) { + case print_base::lc_2: + case print_base::uc_2: + return base::base_2; + case print_base::lc_3: + case print_base::uc_3: + return base::base_3; + case print_base::lc_4: + case print_base::uc_4: + return base::base_4; + case print_base::lc_5: + case print_base::uc_5: + return base::base_5; + case print_base::lc_6: + case print_base::uc_6: + return base::base_6; + case print_base::lc_7: + case print_base::uc_7: + return base::base_7; + case print_base::lc_8: + case print_base::uc_8: + return base::base_8; + case print_base::lc_9: + case print_base::uc_9: + return base::base_9; + case print_base::lc_10: + case print_base::uc_10: + return base::ci_10; + case print_base::lc_11: + case print_base::uc_11: + return base::ci_11; + case print_base::lc_12: + case print_base::uc_12: + return base::ci_12; + case print_base::lc_13: + case print_base::uc_13: + return base::ci_13; + case print_base::lc_14: + case print_base::uc_14: + return base::ci_14; + case print_base::lc_15: + case print_base::uc_15: + return base::ci_15; + case print_base::lc_16: + case print_base::uc_16: + return base::ci_16; + case print_base::lc_17: + case print_base::uc_17: + return base::ci_17; + case print_base::lc_18: + case print_base::uc_18: + return base::ci_18; + case print_base::lc_19: + case print_base::uc_19: + return base::ci_19; + case print_base::lc_20: + case print_base::uc_20: + return base::ci_20; + case print_base::lc_21: + case print_base::uc_21: + return base::ci_21; + case print_base::lc_22: + case print_base::uc_22: + return base::ci_22; + case print_base::lc_23: + case print_base::uc_23: + return base::ci_23; + case print_base::lc_24: + case print_base::uc_24: + return base::ci_24; + case print_base::lc_25: + case print_base::uc_25: + return base::ci_25; + case print_base::lc_26: + case print_base::uc_26: + return base::ci_26; + case print_base::lc_27: + case print_base::uc_27: + return base::ci_27; + case print_base::lc_28: + case print_base::uc_28: + return base::ci_28; + case print_base::lc_29: + case print_base::uc_29: + return base::ci_29; + case print_base::lc_30: + case print_base::uc_30: + return base::ci_30; + case print_base::lc_31: + case print_base::uc_31: + return base::ci_31; + case print_base::lc_32: + case print_base::uc_32: + return base::ci_32; + case print_base::lc_33: + case print_base::uc_33: + return base::ci_33; + case print_base::lc_34: + case print_base::uc_34: + return base::ci_34; + case print_base::lc_35: + case print_base::uc_35: + return base::ci_35; + case print_base::lc_36: + case print_base::uc_36: + return base::ci_36; + case print_base::base_37: + return base::cs_37; + case print_base::base_38: + return base::cs_38; + case print_base::base_39: + return base::cs_39; + case print_base::base_40: + return base::cs_40; + case print_base::base_41: + return base::cs_41; + case print_base::base_42: + return base::cs_42; + case print_base::base_43: + return base::cs_43; + case print_base::base_44: + return base::cs_44; + case print_base::base_45: + return base::cs_45; + case print_base::base_46: + return base::cs_46; + case print_base::base_47: + return base::cs_47; + case print_base::base_48: + return base::cs_48; + case print_base::base_49: + return base::cs_49; + case print_base::base_50: + return base::cs_50; + case print_base::base_51: + return base::cs_51; + case print_base::base_52: + return base::cs_52; + case print_base::base_53: + return base::cs_53; + case print_base::base_54: + return base::cs_54; + case print_base::base_55: + return base::cs_55; + case print_base::base_56: + return base::cs_56; + case print_base::base_57: + return base::cs_57; + case print_base::base_58: + return base::cs_58; + case print_base::base_59: + return base::cs_59; + case print_base::base_60: + return base::cs_60; + case print_base::base_61: + return base::cs_61; + case print_base::base_62: + return base::cs_62; + } + + std::unreachable(); +} + +unsigned long Int::to_ul() { return mpz_get_ui(this->inner); }; +long Int::to_l() { return mpz_get_si(this->inner); }; +double Int::to_d() { return mpz_get_d(this->inner); }; +std::string Int::to_string(print_base base) { + int print_base_int = static_cast(base); + + char *str = mpz_get_str(NULL, print_base_int, this->inner); + + std::string res(str); + + free(str); + + return res; +}; + +void Int::swap(Int &rhs) { mpz_swap(this->inner, rhs.inner); } + +void Int::operator+(const Int &rhs) { + mpz_add(this->inner, this->inner, rhs.inner); +}; + +void Int::operator+(unsigned long rhs) { + mpz_add_ui(this->inner, this->inner, rhs); +}; + +void Int::operator+(long rhs) { + if (rhs < 0) + mpz_sub_ui(this->inner, this->inner, std::abs(rhs)); + else + mpz_add_ui(this->inner, this->inner, rhs); +}; + +void Int::operator-(const Int &rhs) { + mpz_sub(this->inner, this->inner, rhs.inner); +}; + +void Int::operator-(unsigned long rhs) { + mpz_sub_ui(this->inner, this->inner, rhs); +}; + +void Int::operator-(long rhs) { + if (rhs < 0) + mpz_add_ui(this->inner, this->inner, std::abs(rhs)); + else + mpz_sub_ui(this->inner, this->inner, rhs); +}; + +void Int::operator*(const Int &rhs) { + mpz_mul(this->inner, this->inner, rhs.inner); +}; + +void Int::operator*(unsigned long rhs) { + mpz_mul_ui(this->inner, this->inner, rhs); +}; + +void Int::operator*(long rhs) { + if (rhs < 0) { + mpz_mul_ui(this->inner, this->inner, std::abs(rhs)); + this->operator~(); + } else + mpz_mul_ui(this->inner, this->inner, rhs); +}; + +void Int::operator/(const Int &rhs) { + mpz_tdiv_q(this->inner, this->inner, rhs.inner); +}; + +void Int::operator/(unsigned long rhs) { + mpz_tdiv_q_ui(this->inner, this->inner, rhs); +}; + +void Int::operator/(long rhs) { + if (rhs < 0) { + mpz_tdiv_q_ui(this->inner, this->inner, std::abs(rhs)); + this->operator~(); + } else + mpz_tdiv_q_ui(this->inner, this->inner, rhs); +}; + +void Int::operator%(const Int &rhs) { + mpz_mod(this->inner, this->inner, rhs.inner); +}; + +void Int::operator%(unsigned long rhs) { + mpz_mod_ui(this->inner, this->inner, rhs); +}; + +void add_mul(Int &); +void add_mul(unsigned long); +void add_mul(long); + +void sub_mul(Int &); +void sub_mul(unsigned long); +void sub_mul(long); + +void mul_2exp(unsigned long); + +void Int::operator~() { mpz_neg(this->inner, this->inner); }; + +void abs(); + +void ceil_div_quotient(Int &); +void ceil_div_remainder(Int &); +void ceil_div_both(Int &); +void ceil_div(unsigned long); +void ceil_div_both(unsigned long); +void ceil_div_quotient(unsigned long); +void ceil_div_remainder(unsigned long); +void ceil_div(long); +void ceil_div_both(long); +void ceil_div_quotient(long); +void ceil_div_remainder(long); +void ceil_div_quotient_2exp(unsigned long); +void ceil_div_remainder_2exp(unsigned long); + +void floor_div_quotient(Int &); +void floor_div_remainder(Int &); +void floor_div_both(Int &); +void floor_div(unsigned long); +void floor_div_both(unsigned long); +void floor_div_quotient(unsigned long); +void floor_div_remainder(unsigned long); +void floor_div(long); +void floor_div_both(long); +void floor_div_quotient(long); +void floor_div_remainder(long); +void floor_div_quotient_2exp(unsigned long); +void floor_div_remainder_2exp(unsigned long); + +void truncate_div_quotient(Int &); +void truncate_div_remainder(Int &); +void truncate_div_both(Int &); +void truncate_div(unsigned long); +void truncate_div_both(unsigned long); +void truncate_div_quotient(unsigned long); +void truncate_div_remainder(unsigned long); +void truncate_div(long); +void truncate_div_both(long); +void truncate_div_quotient(long); +void truncate_div_remainder(long); +void truncate_div_quotient_2exp(unsigned long); +void truncate_div_remainder_2exp(unsigned long); + +void mod(Int &); +void mod(unsigned long); +void mod(long); + +void div_exact(Int &); +void div_exact(unsigned long); +void div_exact(long); + +int divisible(Int &); +int divisible(unsigned long); +int divisible(long); +int divisible_2exp(unsigned long); + +int congruent(Int &); +int congruent(unsigned long); +int congruent(long); +int congruent_2exp(unsigned long);