├── .gitignore ├── CMakeLists.txt ├── Makefile ├── Readme.md ├── docs ├── bigint.md ├── multiarray.md ├── rational.md ├── timer.md └── unsigned_bigint.md ├── include └── kedixa │ ├── bigint.h │ ├── multiarray.h │ ├── rational.h │ ├── timer.h │ └── unsigned_bigint.h ├── kedixa-config.cmake.in ├── src ├── CMakeLists.txt ├── bigint.cpp ├── rational.cpp └── unsigned_bigint.cpp └── test ├── CMakeLists.txt ├── test_bigint.cpp ├── test_multiarray.cpp ├── test_rational.cpp ├── test_timer.cpp └── test_unsigned_bigint.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore 2 | build.* 3 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | 3 | project( 4 | kedixa 5 | VERSION 0.1.1 6 | LANGUAGES CXX 7 | ) 8 | 9 | set(KEDIXA_LIBRARY_NAME ${PROJECT_NAME}) 10 | set(KEDIXA_LIBRARY_DIR ${PROJECT_BINARY_DIR}/lib) 11 | set(KEDIXA_INCLUDE_DIR ${PROJECT_BINARY_DIR}/include) 12 | set(KEDIXA_INSTALL_CMAKE_FILE ${PROJECT_BINARY_DIR}/${KEDIXA_LIBRARY_NAME}-config.install.cmake) 13 | 14 | set(CMAKE_BUILD_TYPE RelWithDebInfo) 15 | set(CMAKE_SKIP_RPATH TRUE) 16 | set(CMAKE_CXX_STANDARD 11) 17 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") 18 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${KEDIXA_LIBRARY_DIR}) 19 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${KEDIXA_LIBRARY_DIR}) 20 | 21 | file(COPY 22 | ${PROJECT_SOURCE_DIR}/include/kedixa 23 | DESTINATION 24 | ${KEDIXA_INCLUDE_DIR} 25 | ) 26 | 27 | add_subdirectory(src) 28 | 29 | include(GNUInstallDirs) 30 | include(CMakePackageConfigHelpers) 31 | set(LIBRARY_NAME ${KEDIXA_LIBRARY_NAME}) 32 | set(INCLUDE_DIR ${KEDIXA_INCLUDE_DIR}) 33 | set(LIBRARY_DIR ${KEDIXA_LIBRARY_DIR}) 34 | configure_package_config_file( 35 | ${KEDIXA_LIBRARY_NAME}-config.cmake.in 36 | ${PROJECT_BINARY_DIR}/${KEDIXA_LIBRARY_NAME}-config.cmake 37 | INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${KEDIXA_LIBRARY_NAME} 38 | PATH_VARS INCLUDE_DIR LIBRARY_DIR LIBRARY_NAME 39 | ) 40 | 41 | set(INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR}) 42 | set(LIBRARY_DIR ${CMAKE_INSTALL_LIBDIR}) 43 | configure_package_config_file( 44 | ${KEDIXA_LIBRARY_NAME}-config.cmake.in 45 | ${KEDIXA_INSTALL_CMAKE_FILE} 46 | INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${KEDIXA_LIBRARY_NAME} 47 | PATH_VARS INCLUDE_DIR LIBRARY_DIR LIBRARY_NAME 48 | ) 49 | 50 | install(TARGETS 51 | ${KEDIXA_LIBRARY_NAME} 52 | LIBRARY DESTINATION lib 53 | ) 54 | 55 | install(DIRECTORY 56 | ${KEDIXA_INCLUDE_DIR}/kedixa 57 | DESTINATION include) 58 | 59 | install(FILES ${KEDIXA_INSTALL_CMAKE_FILE} 60 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${KEDIXA_LIBRARY_NAME} 61 | RENAME ${KEDIXA_LIBRARY_NAME}-config.cmake 62 | ) 63 | 64 | set(CPACK_GENERATOR "RPM") 65 | set(CPACK_PACKAGE_NAME "kedixa") 66 | set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "kedixa: kedixa's personal c++ toy library") 67 | set(CPACK_PACKAGE_VENDOR "kedixa") 68 | set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION}) 69 | # set(CPACK_RPM_PACKAGE_GROUP "") 70 | set(CPACK_RPM_PACKAGE_URL "https://github.com/kedixa/klibcpp/") 71 | # set(CPACK_RPM_PACKAGE_DESCRIPTION "") 72 | set(CPACK_RPM_PACKAGE_LICENSE "MIT Licence") 73 | set(CPACK_RPM_FILE_NAME RPM-DEFAULT) 74 | set(CPACK_RPM_PACKAGE_RELEASE_DIST ON) 75 | set(CPACK_RPM_PACKAGE_RELEASE "0") 76 | 77 | include(CPack) 78 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CMAKE := $(shell if which cmake3>/dev/null ; then echo cmake3; else echo cmake; fi;) 2 | CPACK := $(shell if which cpack3>/dev/null ; then echo cpack3; else echo cpack; fi;) 3 | ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) 4 | KEDIXA_SRC_DIR := $(ROOT_DIR) 5 | TEST_SRC_DIR := $(ROOT_DIR)/test 6 | KEDIXA_BUILD_DIR := build.kedixa.cmake 7 | TEST_BUILD_DIR := build.test.cmake 8 | RM := rm 9 | 10 | .PHONY: build tests check clean rpm 11 | 12 | build: 13 | mkdir -p $(KEDIXA_BUILD_DIR) 14 | cd $(KEDIXA_BUILD_DIR) && $(CMAKE) $(KEDIXA_SRC_DIR) 15 | make -C $(KEDIXA_BUILD_DIR) -f Makefile 16 | 17 | tests: build 18 | mkdir -p $(TEST_BUILD_DIR) 19 | cd $(TEST_BUILD_DIR) && $(CMAKE) -D kedixa_DIR=$(ROOT_DIR)/$(KEDIXA_BUILD_DIR) $(TEST_SRC_DIR) 20 | make -C $(TEST_BUILD_DIR) -f Makefile 21 | 22 | check: tests 23 | $(TEST_BUILD_DIR)/test_bigint 24 | $(TEST_BUILD_DIR)/test_multiarray 25 | $(TEST_BUILD_DIR)/test_rational 26 | $(TEST_BUILD_DIR)/test_unsigned_bigint 27 | $(TEST_BUILD_DIR)/test_timer 28 | 29 | rpm: build 30 | cd $(KEDIXA_BUILD_DIR) && $(CPACK) 31 | 32 | clean: 33 | $(RM) -rf $(KEDIXA_BUILD_DIR) 34 | $(RM) -rf $(TEST_BUILD_DIR) 35 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # klibcpp 2 | 3 | klibcpp (kedixa's personal c++ toy library) 4 | 5 | # Content 6 | 7 | - timer: 计时器 8 | - multiarray: 多维数组 9 | - unsigned_bigint: 无符号大整数类 10 | - bigint: 带符号大整数类 11 | - rational: 有理数类 12 | 13 | # Compile 14 | ```bash 15 | make build # build library 16 | make check # run tests 17 | make rpm # build rpm package 18 | make clean # remove all build directories 19 | ``` 20 | 21 | # LICENSE 22 | 23 | Apache License 2.0 24 | -------------------------------------------------------------------------------- /docs/bigint.md: -------------------------------------------------------------------------------- 1 | # 带符号大整数 bigint 2 | 3 | ## 简介 4 | 带符号大整数类是一个基于无符号大整数类实现的大整数运算类,主要支持与十进制字符串之间的转换,加、减、乘、除、模等运算,移位操作,前(后)置自增运算符。由于几种位运算暂时没有实际意义,且不经常使用(如果有这样的需求,std::bitset更合适),暂时未实现。各种运算的含义基本与int类型一致。 5 | 6 | ## bigint 7 | 8 | ### 类型定义 9 | ```cpp 10 | using size_type = unsigned_bigint::size_type; 11 | using uint_type = unsigned_bigint::uint_type; 12 | using int_type = unsigned_bigint::int_type; 13 | using ull_type = unsigned_bigint::ull_type; 14 | using llint_type = unsigned_bigint::llint_type; 15 | ``` 16 | 17 | ### 构造函数 18 | ```cpp 19 | bigint(const int_type number = 0 ); 20 | bigint(const unsigned_bigint&, bool sign = false ); 21 | bigint(unsigned_bigint&&, bool sign = false ); 22 | bigint(const std::string& ); 23 | bigint(const char* ); 24 | bigint(const bigint& ); 25 | bigint(bigint&& ); 26 | ``` 27 | 28 | ### 赋值运算符 29 | ```cpp 30 | bigint& operator= (const bigint& ); 31 | bigint& operator= (bigint&& ); 32 | bigint& operator+= (const int_type ); 33 | bigint& operator+= (const bigint& ); 34 | bigint& operator-= (const int_type ); 35 | bigint& operator-= (const bigint& ); 36 | bigint& operator*= (const int_type ); 37 | bigint& operator*= (const bigint& ); 38 | bigint& operator/= (const int_type ); 39 | bigint& operator/= (const bigint& ); 40 | bigint& operator%= (const int_type ); 41 | bigint& operator%= (const bigint& ); 42 | ``` 43 | 注:当除数为零时,抛出std::runtime_error异常。 44 | 45 | ### 类型转换函数 46 | ```cpp 47 | explicit operator bool() const noexcept; 48 | explicit operator int_type() const noexcept; 49 | explicit operator llint_type() const noexcept; 50 | explicit operator unsigned_bigint() const noexcept; 51 | 52 | int_type to_int() const ; 53 | llint_type to_ll() const ; 54 | long double to_ld() const ; 55 | unsigned_bigint to_ubigint() const ; 56 | ``` 57 | 注:当数为零时,operator bool()返回false, 否则返回true。当数确实为一个int或long long可以容纳的数时,operator int_type() 和 operator llint_type() 返回正确的数,否则为未定义行为,而转换失败时 to_int() 和 to_ll() 则抛出std::runtime_error异常。operator unsigned_bigint() 和to_ubigint() 返回与数的绝对值相同的无符号整数。 to_ld() 返回大整数的浮点数表示,溢出时抛出 std::runtime_error异常。 58 | 59 | ### 算术运算符 60 | ```cpp 61 | friend bigint operator+ (const bigint&, const bigint&); 62 | friend bigint operator- (const bigint&, const bigint&); 63 | friend bigint operator* (const bigint&, const bigint&); 64 | friend bigint operator/ (const bigint&, const bigint&); 65 | friend bigint operator% (const bigint&, const bigint&); 66 | 67 | bigint& operator++(); 68 | bigint& operator--(); 69 | bigint operator++(int); 70 | bigint operator--(int); 71 | bigint operator+ () const; 72 | bigint operator- () const; 73 | ``` 74 | 注:当除数为零时,抛出 std::runtime_error异常。 75 | 76 | ### 关系运算符 77 | 包括大于、大于等于、小于、小于等于、等于、不等于六种关系运算符,与内置整数的关系运算具有相同的定义。 78 | 79 | ### 其它函数 80 | ```cpp 81 | int compare(const bigint& ) const noexcept; 82 | 83 | bigint add(const bigint& ) const; 84 | bigint& add_eq(const bigint& ) ; 85 | bigint sub(const bigint& ) const; 86 | bigint& sub_eq(const bigint& ) ; 87 | bigint multi(const bigint& ) const; 88 | bigint& multi_eq(const bigint& ) ; 89 | bigint div(const bigint& ) const; 90 | bigint& div_eq(const bigint& ) ; 91 | bigint mod(const bigint& ) const; 92 | bigint& mod_eq(const bigint& ) ; 93 | 94 | std::pair div_mod(const bigint&) const; 95 | 96 | void opposite() noexcept; 97 | void swap(bigint &) noexcept; 98 | size_t size() const noexcept; 99 | std::string to_string(bool reverse = false) const; 100 | ``` 101 | - compare 比较两个大整数,返回值<0、==0、>0分别表示*this <、==、 >另一个大整数。 102 | - swap 用于交换两个大整数,时间复杂度为常数。 103 | - size 返回无符号大整数的size()。 104 | - to_string 将大整数转换成字符串。 105 | - opposite 将*this 转换成相反数。 106 | 107 | ### 析构函数 108 | ```cpp 109 | ~bigint() noexcept; 110 | ``` 111 | 112 | ### 哈希函数 113 | 可以通过C++提供的哈希类获取一个大整数的哈希值,以便于将大整数放置于标准库中的无序容器中。 114 | -------------------------------------------------------------------------------- /docs/multiarray.md: -------------------------------------------------------------------------------- 1 | # 多维数组 multi array 2 | 3 | ## 简介 4 | 5 | multiarray 是一个多维数组,位于 include/multiarray.h ,用于方便地定义和使用多维度的动态数组, 6 | 数组的每个维度的长度是在运行时确定的,一旦确定便不可更改(否则就成了std::vector), 7 | 且数组的维度必须是一个编译器常量。 8 | 9 | ## multiarray 10 | ```cpp 11 | template> 12 | class multiarray; 13 | ``` 14 | 15 | ### 模板参数 16 | - T: 数组要保存的元素的类型 17 | - N: 数组的维度,无符号整数 18 | - Alloc: 空间分配器,默认为 std::allocator 19 | 20 | ### 成员函数 21 | #### 构造函数 22 | ```cpp 23 | template 24 | multiarray(size_type sz, Args&&... args); 25 | 26 | multiarray(multiarray&& ma); 27 | 28 | multiarray(const multiarray&) = delete; 29 | ``` 30 | 1. 使用每个维度的长度构造数组,剩余的参数用于构造对象; 31 | 2. 使用另一个多维数组进行移动构造; 32 | 3. 不支持拷贝构造。 33 | 34 | Example: 35 | ```cpp 36 | // 构造一个 2 * 3 * 4 的整型数组,并用 9 初始化 37 | multiarray int_array(2, 3, 4, 9); 38 | 39 | // 构造一个 100 的双精度浮点数数组,并用 3.14 初始化 40 | multiarray double_array(100, 3.14); 41 | ``` 42 | 43 | #### operator= 44 | ```cpp 45 | multiarray& operator=(multiarray&& ma); 46 | multiarray& operator=(const multiarray&) = delete; 47 | ``` 48 | 1. 使用另一个多维数组进行移动赋值; 49 | 2. 不支持拷贝赋值。 50 | 51 | Example: 52 | ```cpp 53 | multiarray array1(3, 3); 54 | multiarray array2(0, 0); 55 | array2 = std::move(array1); 56 | // array1 no longer usable. 57 | ``` 58 | 59 | #### 迭代器 60 | ```cpp 61 | begin() // 第一个元素的迭代器 62 | end() // 最后一个元素之后的迭代器 63 | cbegin() // 常量迭代器 64 | cend() // 常量迭代器 65 | 66 | // Example: 67 | multiarray int_array(100); 68 | for(auto &i : int_array) 69 | i = 0; 70 | ``` 71 | 72 | #### 容量 73 | ```cpp 74 | constexpr unsigned dimension() const; // 返回当前数组的维度 75 | size_type size() const; // 返回当前维度的长度 76 | 77 | Example: 78 | multiarray int_array(4, 5, 6); 79 | int_array.dimension() == 3; 80 | int_array.size() == 4; 81 | 82 | int_array[0].dimension() == 2; 83 | int_array[0].size() == 5; 84 | ``` 85 | 86 | #### 析构函数 87 | ```cpp 88 | ~multiarray() // 析构所有对象并释放空间 89 | ``` 90 | -------------------------------------------------------------------------------- /docs/rational.md: -------------------------------------------------------------------------------- 1 | # 有理数类 rational 2 | 3 | ## 简介 4 | 有理数类是一个基于无符号大整数类实现的有理数运算类,由于每个有理数恰好可以表示为一个最简分数,因此采用两个无符号大整数以及一个符号位即可表示有理数。 rational 有理数类支持四则运算,关系运算等。 各种运算的含义与分数的运算一致。 5 | 6 | ## rational 7 | 8 | ### 类型定义 9 | ```cpp 10 | using size_type = unsigned_bigint::size_type; 11 | using uint_type = unsigned_bigint::uint_type; 12 | using int_type = unsigned_bigint::int_type; 13 | using ull_type = unsigned_bigint::ull_type; 14 | using llint_type= unsigned_bigint::llint_type; 15 | using ubigint = unsigned_bigint; 16 | ``` 17 | 18 | ### 构造函数 19 | ```cpp 20 | rational(const ubigint &n = ubigint(0u), const ubigint &d = ubigint(1u), bool sign = false); 21 | rational(ubigint&&, ubigint&&, bool); 22 | rational(const rational&); 23 | rational(rational&&); 24 | ``` 25 | 26 | ### 赋值运算符 27 | ```cpp 28 | rational& operator= (const rational&); 29 | rational& operator= (rational&&); 30 | rational& operator+=(const rational&); 31 | rational& operator-=(const rational&); 32 | rational& operator*=(const rational&); 33 | rational& operator/=(const rational&); 34 | ``` 35 | 注:当除数为零时,抛出std::runtime_error异常。 36 | 37 | ### 类型转换函数 38 | ```cpp 39 | explicit operator bool() const noexcept; 40 | long double to_ld() const; 41 | ``` 42 | 注:当有理数为零时, operator bool()返回false, 否则返回true。 to_ld() 返回有理数的浮点数表示,若分母或分子不能表示成long double 类型,抛出 std::runtime_error异常。 43 | 44 | ### 算术运算符 45 | ```cpp 46 | friend rational operator+ (const rational&, const rational&); 47 | friend rational operator- (const rational&, const rational&); 48 | friend rational operator* (const rational&, const rational&); 49 | friend rational operator/ (const rational&, const rational&); 50 | 51 | rational operator+ () const; 52 | rational operator- () const; 53 | ``` 54 | 注:当除数为零时,抛出std::runtime_error异常。 55 | 56 | ### 关系运算符 57 | 包括大于、大于等于、小于、小于等于、等于、不等于六种关系运算符,与分数的关系运算具有相同的定义。 58 | 59 | ### 其它函数 60 | ```cpp 61 | int compare(const rational&) const; 62 | 63 | rational add (const rational&) const; 64 | rational& add_eq(const rational&); 65 | rational sub (const rational&) const; 66 | rational& sub_eq(const rational&); 67 | rational multi (const rational&) const; 68 | rational& multi_eq(const rational&); 69 | rational div (const rational&) const; 70 | rational& div_eq(const rational&); 71 | 72 | ubigint get_num() const; 73 | ubigint get_den() const; 74 | bool get_sign() const; 75 | void approximate(size_type hint = 0); 76 | void opposite() noexcept; // *this = -*this 77 | void reciprocal(); // *this = this->den/this->num 78 | void swap(rational&) noexcept; 79 | size_type num_size() const noexcept; 80 | size_type den_size() const noexcept; 81 | std::string to_string(bool reverse = false) const; 82 | std::string to_decimal(size_type decimal_digits = 16, bool reverse = false) const; 83 | ``` 84 | - compare 比较两个有理数,返回值<0、==0、>0分别表示*this <、==、 >另一个有理数。 85 | - swap 用于交换两个有理数,时间复杂度为常数。 86 | - get_num 获取分子。 87 | - get_den 获取分母。 88 | - get_sign 获取符号位。 89 | - approximate 将分子分母同时至少缩小hint * pow(2, 8*sizeof(unsigned))倍, 获得其近似表示。 90 | - opposite 将*this 转换成相反数。 91 | - reciprocal 转换成倒数,若数为零则抛出std::runtime_error异常。 92 | - num_size 返回分子的size。 93 | - den_size 返回分母的size。 94 | - to_string 将有理数转换成分数表示的字符串,如1/2, -3/2, -7等。 95 | - to_decimal 将分数化为有decimal_digits 个小数位的小数表示,位数不足补零。 96 | 97 | ### 析构函数 98 | ```cpp 99 | ~rational() noexcept; 100 | ``` 101 | ### 哈希函数 102 | 可以通过C++提供的哈希类获取一个有理数的哈希值,以便于将有理数放置于标准库中的无序容器中。 103 | -------------------------------------------------------------------------------- /docs/timer.md: -------------------------------------------------------------------------------- 1 | # 计时器 timer 2 | 3 | 用于计算程序中某些步骤耗费的时间。 4 | 5 | ## 静态函数 6 | - int64_t timeit(f, args...) 计算函数f的运行时间,返回使用的纳秒数 7 | - int64_t monotonic_nsec() 8 | - int64_t monotonic_usec() 9 | - int64_t monotonic_msec() 10 | 11 | ## 成员函数 12 | - timer() 构造计时器对象,并开始计时 13 | - void start() 开始计时,或重新开始计时 14 | - void pause() 暂停计时 15 | - void reset() 重置计时器,与构造时状态一致 16 | - double stop() 停止计时,并返回当前累计的时间(秒) 17 | - int64_t as_nsec() 返回当前累计的纳秒数 18 | - int64_t as_usec() 返回当前累计的微秒数 19 | - int64_t as_msec() 返回当前累计的毫秒数 20 | -------------------------------------------------------------------------------- /docs/unsigned_bigint.md: -------------------------------------------------------------------------------- 1 | # 无符号大整数 unsigned_bigint 2 | 3 | ## 简介 4 | 无符号大整数类是一个支持无符号大整数运算的类,主要支持与十进制字符串之间的转换,加、减、乘、除、模等四则运算,逻辑移位、与、或、异或等位操作,由于按位取反在无符号大整数中没有实际意义,因此没有实现。各种运算的含义均与unsigned int的运算具有相似的意义,略有不同的地方将在下文指出。 5 | 6 | ## unsigned_bigint 7 | 8 | ### 类型定义 9 | ```cpp 10 | using size_type = size_t; 11 | using uint_type = uint32_t; 12 | using int_type = int32_t; 13 | using ull_type = uint64_t; 14 | using llint_type = int64_t; 15 | ``` 16 | 17 | ### 构造函数 18 | ```cpp 19 | unsigned_bigint(const uint_type number = 0 ); 20 | unsigned_bigint(const vector& ); 21 | unsigned_bigint(vector&& ); 22 | unsigned_bigint(const std::string& ); 23 | unsigned_bigint(const char* ); 24 | unsigned_bigint(const unsigned_bigint& ); 25 | unsigned_bigint(unsigned_bigint&& ); 26 | ``` 27 | 28 | ### 赋值运算符 29 | ```cpp 30 | unsigned_bigint& operator= (const unsigned_bigint& ); 31 | unsigned_bigint& operator= (unsigned_bigint&& ); 32 | unsigned_bigint& operator+= (const uint_type ); 33 | unsigned_bigint& operator+= (const unsigned_bigint& ); 34 | unsigned_bigint& operator-= (const uint_type ); 35 | unsigned_bigint& operator-= (const unsigned_bigint& ); 36 | unsigned_bigint& operator*= (const uint_type ); 37 | unsigned_bigint& operator*= (const unsigned_bigint& ); 38 | unsigned_bigint& operator/= (const uint_type ); 39 | unsigned_bigint& operator/= (const unsigned_bigint& ); 40 | unsigned_bigint& operator%= (const uint_type ); 41 | unsigned_bigint& operator%= (const unsigned_bigint& ); 42 | unsigned_bigint& operator&= (const unsigned_bigint& ); 43 | unsigned_bigint& operator|= (const unsigned_bigint& ); 44 | unsigned_bigint& operator^= (const unsigned_bigint& ); 45 | unsigned_bigint& operator<<=(const size_type ); 46 | unsigned_bigint& operator>>=(const size_type)noexcept; 47 | ``` 48 | 注:当减法向下溢出时,抛出std::underflow_error 异常;当除数为零时,抛出std::runtime_error 异常。当减法向下溢出时,被减数的状态是未知的。 49 | 50 | ### 类型转换函数 51 | ```cpp 52 | explicit operator bool() const noexcept; 53 | explicit operator uint_type() const noexcept; 54 | explicit operator ull_type() const noexcept; 55 | 56 | uint_type to_uint() const; 57 | ull_type to_ull() const; 58 | long double to_ld() const; 59 | ``` 60 | 当数为零时,operator bool()返回假,否则返回真。operator uint_type() 返回与 unsigned_bigint::uint_type 字长相同的整数,当溢出时整数被截断,operator ull_type() 返回与unsigned_bigint::ull_type 字长相同的整数,当溢出时截断。 61 | to_uint() 返回与unsigned_bigint::uint_type 字长相同的整数,当溢出时抛出 std::runtime_error 异常,to_ull() 返回与unsigned_bigint::ull_type 字长相同的整数,当溢出时抛出 std::runtime_error 异常,to_ld() 返回大整数的长浮点数表示,当溢出时抛出 std::runtime_error 异常。 62 | 63 | ### 算术运算符 64 | 加、减、乘、除、模等运算,包括无符号大整数与无符号大整数、无符号大整数与C++内置无符号整数之间的运算,以加法为例: 65 | ```cpp 66 | friend unsigned_bigint operator+ (const unsigned_bigint&, const unsigned_bigint& ); 67 | friend unsigned_bigint operator+ (const unsigned_bigint&, unsigned_bigint&& ); 68 | friend unsigned_bigint operator+ (unsigned_bigint&&, const unsigned_bigint& ); 69 | friend unsigned_bigint operator+ (unsigned_bigint&&, unsigned_bigint&& ); 70 | friend unsigned_bigint operator+ (const unsigned_bigint&, const uint_type ); 71 | friend unsigned_bigint operator+ (const uint_type, const unsigned_bigint& ); 72 | friend unsigned_bigint operator+ (unsigned_bigint&&, const uint_type ); 73 | friend unsigned_bigint operator+ (const uint_type, unsigned_bigint&& ); 74 | ``` 75 | 注:当减法向下溢出时,抛出std::underflow_error 异常;当除数为零时,抛出std::runtime_error 异常。 76 | 还包括前置自增自减以及后置自增自减运算符。 77 | 78 | ### 位运算 79 | ```cpp 80 | friend unsigned_bigint operator<<(const unsigned_bigint&, size_type ); 81 | friend unsigned_bigint operator<<(unsigned_bigint&&, size_type ); 82 | friend unsigned_bigint operator>>(const unsigned_bigint&, size_type ); 83 | friend unsigned_bigint operator>>(unsigned_bigint&&, size_type ); 84 | friend unsigned_bigint operator& (const unsigned_bigint&, const unsigned_bigint& ); 85 | friend unsigned_bigint operator& (const unsigned_bigint&, unsigned_bigint&& ); 86 | friend unsigned_bigint operator& (unsigned_bigint&&, const unsigned_bigint& ); 87 | friend unsigned_bigint operator& (unsigned_bigint&&, unsigned_bigint&& ); 88 | friend unsigned_bigint operator| (const unsigned_bigint&, const unsigned_bigint& ); 89 | friend unsigned_bigint operator| (const unsigned_bigint&, unsigned_bigint&& ); 90 | friend unsigned_bigint operator| (unsigned_bigint&&, const unsigned_bigint& ); 91 | friend unsigned_bigint operator| (unsigned_bigint&&, unsigned_bigint&& ); 92 | friend unsigned_bigint operator^ (const unsigned_bigint&, const unsigned_bigint& ); 93 | friend unsigned_bigint operator^ (const unsigned_bigint&, unsigned_bigint&& ); 94 | friend unsigned_bigint operator^ (unsigned_bigint&&, const unsigned_bigint& ); 95 | friend unsigned_bigint operator^ (unsigned_bigint&&, unsigned_bigint&& ); 96 | ``` 97 | 位运算的结果与内置无符号整数位运算具有相同的定义。 98 | 99 | ### 关系运算符 100 | 包括大于、大于等于、小于、小于等于、等于、不等于六种关系运算符,与内置无符号整数的关系运算具有相同的定义。 101 | 102 | ### 其它函数 103 | ```cpp 104 | int compare(const unsigned_bigint&) const noexcept; 105 | 106 | unsigned_bigint add(const unsigned_bigint& ) const; 107 | unsigned_bigint add(const uint_type ) const; 108 | unsigned_bigint& add_eq(const unsigned_bigint& ); 109 | unsigned_bigint& add_eq(const uint_type ); 110 | 111 | unsigned_bigint sub(const unsigned_bigint& ) const; 112 | unsigned_bigint sub(const uint_type ) const; 113 | unsigned_bigint& sub_eq(const unsigned_bigint& ); 114 | unsigned_bigint& sub_eq(const uint_type ); 115 | 116 | unsigned_bigint multi(const unsigned_bigint& ) const; 117 | unsigned_bigint multi(const uint_type ) const; 118 | unsigned_bigint& multi_eq(const unsigned_bigint& ); 119 | unsigned_bigint& multi_eq(const uint_type ); 120 | 121 | unsigned_bigint div(const unsigned_bigint& ) const; 122 | unsigned_bigint div(const uint_type ) const; 123 | unsigned_bigint& div_eq(const unsigned_bigint& ); 124 | unsigned_bigint& div_eq(const uint_type ); 125 | 126 | unsigned_bigint mod(const unsigned_bigint& ) const; 127 | unsigned_bigint mod(const uint_type ) const; 128 | unsigned_bigint& mod_eq(const unsigned_bigint& ); 129 | unsigned_bigint& mod_eq(const uint_type ); 130 | 131 | std::pair div_mod(const unsigned_bigint&) const; 132 | std::pair div_mod(const uint_type ) const; 133 | 134 | void swap(unsigned_bigint&) noexcept; 135 | size_t size() const noexcept; 136 | std::string to_string(bool reverse = false) const; 137 | ``` 138 | - compare函数将无符号大整数与另一个无符号大整数相比较,返回值<0、==0、>0分别表示*this <、==、>另一个无符号大整数。 139 | - add、sub、multi、div等函数与四则运算相同,div_mod用于同时返回商和余数。 140 | - swap函数交换两个无符号大整数,时间复杂度为常数。 141 | - size返回内部std::vector的size。 142 | - to_string将无符号大整数转换成字符串,如果参数为true,则返回反转的字符串。 143 | 144 | ### 析构函数 145 | ```cpp 146 | ~unsigned_bigint() noexcept; 147 | ``` 148 | 149 | ### 哈希函数 150 | 可以通过C++提供的哈希类获取一个无符号大整数的哈希值,以便于将无符号大整数放置于标准库中的无序容器中。 151 | -------------------------------------------------------------------------------- /include/kedixa/bigint.h: -------------------------------------------------------------------------------- 1 | #ifndef KEDIXA_BIGINT_H 2 | #define KEDIXA_BIGINT_H 3 | 4 | #include "kedixa/unsigned_bigint.h" 5 | 6 | namespace kedixa { 7 | 8 | class bigint { 9 | public: 10 | using size_type = unsigned_bigint::size_type; 11 | using uint_type = unsigned_bigint::uint_type; 12 | using int_type = unsigned_bigint::int_type; 13 | using ull_type = unsigned_bigint::ull_type; 14 | using llint_type = unsigned_bigint::llint_type; 15 | 16 | private: 17 | unsigned_bigint ubig; 18 | bool sign; // 0 for +, 1 for - 19 | 20 | public: 21 | // constructors 22 | bigint(const int_type number = 0 ); 23 | bigint(const unsigned_bigint&, bool sign = false ); 24 | bigint(unsigned_bigint&&, bool sign = false ); 25 | explicit 26 | bigint(const std::string& ); 27 | explicit 28 | bigint(const char* ); 29 | bigint(const bigint& ); 30 | bigint(bigint&& ); 31 | 32 | // assignment operators 33 | bigint& operator= (const bigint& ); 34 | bigint& operator= (bigint&& ); 35 | bigint& operator+= (const int_type ); 36 | bigint& operator+= (const bigint& ); 37 | bigint& operator-= (const int_type ); 38 | bigint& operator-= (const bigint& ); 39 | bigint& operator*= (const int_type ); 40 | bigint& operator*= (const bigint& ); 41 | bigint& operator/= (const int_type ); 42 | bigint& operator/= (const bigint& ); 43 | bigint& operator%= (const int_type ); 44 | bigint& operator%= (const bigint& ); 45 | 46 | // conversion operators 47 | explicit operator bool() const noexcept; 48 | explicit operator int_type() const noexcept; 49 | explicit operator llint_type() const noexcept; 50 | explicit operator unsigned_bigint() const noexcept; 51 | 52 | // conversion functions 53 | int_type to_int() const ; 54 | llint_type to_ll() const ; 55 | long double to_ld() const ; 56 | unsigned_bigint to_ubigint() const ; 57 | 58 | // arithmetic operators 59 | friend bigint operator+ (const bigint&, const bigint&); 60 | friend bigint operator- (const bigint&, const bigint&); 61 | friend bigint operator* (const bigint&, const bigint&); 62 | friend bigint operator/ (const bigint&, const bigint&); 63 | friend bigint operator% (const bigint&, const bigint&); 64 | 65 | bigint& operator++(); 66 | bigint& operator--(); 67 | bigint operator++(int); 68 | bigint operator--(int); 69 | bigint operator+ () const; 70 | bigint operator- () const; 71 | 72 | // bitwise operators 73 | friend bigint operator<<(const bigint&, size_type); 74 | friend bigint operator>>(const bigint&, size_type); 75 | 76 | // relational operators 77 | friend bool operator< (const bigint&, const bigint&) noexcept; 78 | friend bool operator==(const bigint&, const bigint&) noexcept; 79 | friend bool operator<=(const bigint&, const bigint&) noexcept; 80 | friend bool operator> (const bigint&, const bigint&) noexcept; 81 | friend bool operator>=(const bigint&, const bigint&) noexcept; 82 | friend bool operator!=(const bigint&, const bigint&) noexcept; 83 | 84 | // others 85 | int compare(const bigint& ) const noexcept; 86 | 87 | bigint add (const bigint& ) const; 88 | bigint& add_eq(const bigint& ) ; 89 | bigint sub (const bigint& ) const; 90 | bigint& sub_eq(const bigint& ) ; 91 | bigint multi (const bigint& ) const; 92 | bigint& multi_eq(const bigint& ) ; 93 | bigint div (const bigint& ) const; 94 | bigint& div_eq(const bigint& ) ; 95 | bigint mod (const bigint& ) const; 96 | bigint& mod_eq(const bigint& ) ; 97 | 98 | std::pair div_mod(const bigint&) const; 99 | 100 | void opposite() noexcept; // *this = - *this; 101 | void swap(bigint &) noexcept; 102 | size_type size() const noexcept; 103 | std::string to_string(bool reverse = false) const; 104 | ~bigint() noexcept; 105 | 106 | friend std::hash; 107 | }; // class bigint 108 | 109 | void swap(bigint&, bigint&) noexcept; 110 | 111 | } // namespace kedixa 112 | 113 | // specialize std::hash 114 | namespace std { 115 | template<> struct hash { 116 | size_t operator()(const kedixa::bigint &big) const { 117 | size_t hash_code = hash()(big.ubig); 118 | if(big.sign) 119 | hash_code = (~hash_code + 1); 120 | 121 | return hash_code; 122 | } 123 | }; 124 | 125 | } // namespace std 126 | 127 | #endif // KEDIXA_BIGINT_H 128 | -------------------------------------------------------------------------------- /include/kedixa/multiarray.h: -------------------------------------------------------------------------------- 1 | #ifndef KEDIXA_MULTI_ARRAY_H 2 | #define KEDIXA_MULTI_ARRAY_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace kedixa { 9 | 10 | // Forward declaration for multiarray. 11 | template 12 | class multiarray; 13 | 14 | namespace { 15 | // Help multiarray derive subarray type. 16 | template 17 | struct _subarray_type { 18 | using value_type = multiarray; 19 | }; 20 | 21 | template 22 | struct _subarray_type { 23 | using value_type = T; 24 | }; 25 | 26 | template 27 | struct _subarray_type 28 | { }; 29 | 30 | } // namespace 31 | 32 | template> 33 | class multiarray { 34 | public: 35 | using size_type = size_t; 36 | using value_type = typename _subarray_type::value_type; 37 | using pointer = value_type*; 38 | using const_pointer = const value_type*; 39 | using reference = value_type&; 40 | using const_reference = const value_type&; 41 | using allocator_type = typename Alloc::template rebind::other; 42 | 43 | template 44 | multiarray(size_type sz, Args&&... args) noexcept { 45 | static_assert(sizeof...(args) >= N-1, 46 | "Number of parameters for kedixa::multiarray incorrect."); 47 | 48 | // Note: sz may be zero 49 | _data.array_size = sz; 50 | _data.value = _data.allocate(sz); 51 | 52 | // TODO exception safe 53 | for(size_t i = 0; i < _data.array_size; ++i) 54 | _data.construct(_data.value + i, std::forward(args)...); 55 | } 56 | 57 | multiarray(const multiarray&) = delete; 58 | multiarray(multiarray&& ma) noexcept { 59 | _data.value = ma._data.value; 60 | _data.array_size = ma._data.array_size; 61 | 62 | ma._data.value = nullptr; 63 | ma._data.array_size = 0; 64 | } 65 | 66 | multiarray& operator=(const multiarray&) = delete; 67 | multiarray& operator=(multiarray&& ma) noexcept { 68 | if(this != &ma) 69 | std::swap(_data, ma._data); 70 | return *this; 71 | } 72 | 73 | constexpr unsigned dimension() const noexcept 74 | { return N; } 75 | 76 | size_type size() const noexcept 77 | { return _data.array_size; } 78 | 79 | pointer begin() noexcept 80 | { return _data.value; } 81 | 82 | const_pointer cbegin() const noexcept 83 | { return _data.value; } 84 | 85 | pointer end() noexcept 86 | { return _data.value + _data.array_size; } 87 | 88 | const_pointer cend() const noexcept 89 | { return _data.value + _data.array_size; } 90 | 91 | reference operator[](size_type pos) noexcept 92 | { return _data.value[pos]; } 93 | 94 | const_reference operator[](size_type pos) const noexcept 95 | { return _data.value[pos]; } 96 | 97 | ~multiarray() noexcept { 98 | for(size_t i = 0; i < _data.array_size; ++i) 99 | _data.destroy(_data.value + i); 100 | _data.deallocate(_data.value, _data.array_size); 101 | } 102 | 103 | private: 104 | struct _multiarray_data : allocator_type { 105 | pointer value; 106 | size_type array_size; 107 | }; 108 | 109 | _multiarray_data _data; 110 | }; 111 | 112 | template 113 | class multiarray { 114 | public: 115 | // Help user find zero dimension error, 116 | // rather than tons of template error. 117 | template 118 | multiarray(Args&&... args) = delete; 119 | }; 120 | 121 | } // namespace kedixa 122 | 123 | #endif // KEDIXA_MULTI_ARRAY_H 124 | -------------------------------------------------------------------------------- /include/kedixa/rational.h: -------------------------------------------------------------------------------- 1 | #ifndef KEDIXA_RATIONAL_H 2 | #define KEDIXA_RATIONAL_H 3 | 4 | #include "kedixa/unsigned_bigint.h" 5 | 6 | namespace kedixa { 7 | 8 | class rational { 9 | public: 10 | using size_type = unsigned_bigint::size_type; 11 | using uint_type = unsigned_bigint::uint_type; 12 | using int_type = unsigned_bigint::int_type; 13 | using ull_type = unsigned_bigint::ull_type; 14 | using llint_type= unsigned_bigint::llint_type; 15 | using ubigint = unsigned_bigint; 16 | 17 | public: 18 | // constructors 19 | rational(const ubigint &n = ubigint(0u), const ubigint &d = ubigint(1u), bool sign = false); 20 | rational(ubigint&&, ubigint&&, bool); 21 | rational(const rational&); 22 | rational(rational&&); 23 | 24 | // assignment operators 25 | rational& operator= (const rational&); 26 | rational& operator= (rational&&); 27 | rational& operator+=(const rational&); 28 | rational& operator-=(const rational&); 29 | rational& operator*=(const rational&); 30 | rational& operator/=(const rational&); 31 | 32 | // conversion operators 33 | explicit operator bool() const noexcept; 34 | 35 | // conversion functions 36 | long double to_ld() const; 37 | 38 | // arithmetic operators 39 | friend rational operator+ (const rational&, const rational&); 40 | friend rational operator- (const rational&, const rational&); 41 | friend rational operator* (const rational&, const rational&); 42 | friend rational operator/ (const rational&, const rational&); 43 | 44 | rational operator+ () const; 45 | rational operator- () const; 46 | 47 | // relational operators 48 | friend bool operator< (const rational&, const rational&); 49 | friend bool operator==(const rational&, const rational&) noexcept; 50 | friend bool operator<=(const rational&, const rational&); 51 | friend bool operator> (const rational&, const rational&); 52 | friend bool operator>=(const rational&, const rational&); 53 | friend bool operator!=(const rational&, const rational&) noexcept; 54 | 55 | // others 56 | int compare(const rational&) const; 57 | 58 | rational add (const rational&) const; 59 | rational& add_eq(const rational&); 60 | rational sub (const rational&) const; 61 | rational& sub_eq(const rational&); 62 | rational multi (const rational&) const; 63 | rational& multi_eq(const rational&); 64 | rational div (const rational&) const; 65 | rational& div_eq(const rational&); 66 | 67 | ubigint get_num() const; // return numerator 68 | ubigint get_den() const; // return denominator 69 | bool get_sign() const; // return sign 70 | // reduce the rational to a approximate one, to save space and time, 71 | // DON'T use it if you need a exact number. 72 | void approximate(size_type hint = 0); 73 | void opposite() noexcept; // *this = -*this 74 | void reciprocal(); // *this = this->den/this->num 75 | void swap(rational&) noexcept; 76 | size_type num_size() const noexcept; 77 | size_type den_size() const noexcept; 78 | std::string to_string(bool reverse = false) const; 79 | std::string to_decimal(size_type decimal_digits = 16, bool reverse = false) const; 80 | ~rational() noexcept; 81 | 82 | friend std::hash; 83 | 84 | private: 85 | ubigint num; // numerator 86 | ubigint den; // denominator 87 | bool sign; // 0 for +, 1 for - 88 | 89 | static ubigint gcd(ubigint x, ubigint y); 90 | void reduce(); // reduce the fraction 91 | }; // class rational 92 | 93 | void swap(rational&, rational&) noexcept; 94 | 95 | } // namespace kedixa 96 | 97 | namespace std { 98 | template<> struct hash { 99 | size_t operator()(const kedixa::rational &rat) const { 100 | auto h = hash(); 101 | size_t hash_code = h(rat.num) ^ h(rat.den); 102 | if(rat.sign) 103 | hash_code = (~hash_code + 1); 104 | 105 | return hash_code; 106 | } 107 | }; 108 | 109 | } // namespace std 110 | 111 | #endif // KEDIXA_RATIONAL_H 112 | -------------------------------------------------------------------------------- /include/kedixa/timer.h: -------------------------------------------------------------------------------- 1 | #ifndef KEDIXA_TIMER_H 2 | #define KEDIXA_TIMER_H 3 | 4 | #include 5 | #include 6 | 7 | namespace kedixa { 8 | 9 | class timer { 10 | constexpr static int64_t NANO_PER_SEC = 1000000000; 11 | 12 | public: 13 | static int64_t monotonic_nsec() { 14 | auto now = std::chrono::steady_clock::now(); 15 | return std::chrono::duration_cast(now.time_since_epoch()).count(); 16 | } 17 | 18 | static int64_t monotonic_usec() { 19 | auto now = std::chrono::steady_clock::now(); 20 | return std::chrono::duration_cast(now.time_since_epoch()).count(); 21 | } 22 | 23 | static int64_t monotonic_msec() { 24 | auto now = std::chrono::steady_clock::now(); 25 | return std::chrono::duration_cast(now.time_since_epoch()).count(); 26 | } 27 | 28 | // return nano seconds cost by calling f(args...); 29 | template 30 | static int64_t timeit(F&& f, Args&&... args) { 31 | timer t; 32 | std::forward(f)(std::forward(args)...); 33 | t.stop(); 34 | return t.as_nsec(); 35 | } 36 | 37 | public: 38 | timer() : begin_nsec(monotonic_nsec()), total_nsec(0) { } 39 | timer(const timer &) = default; 40 | timer& operator= (const timer &) = default; 41 | 42 | void start() { 43 | begin_nsec = monotonic_nsec(); 44 | } 45 | 46 | void pause() { 47 | int64_t end_nsec = monotonic_nsec(); 48 | total_nsec += (end_nsec - begin_nsec); 49 | } 50 | 51 | void reset() { 52 | begin_nsec = monotonic_nsec(); 53 | total_nsec = 0; 54 | } 55 | 56 | // return total seconds with type double 57 | double stop() { 58 | int64_t end_nsec = monotonic_nsec(); 59 | total_nsec += (end_nsec - begin_nsec); 60 | return double(total_nsec) / NANO_PER_SEC; 61 | } 62 | 63 | int64_t as_nsec() { 64 | return total_nsec; 65 | } 66 | 67 | int64_t as_usec() { 68 | return total_nsec / 1000; 69 | } 70 | 71 | int64_t as_msec() { 72 | return total_nsec / 1000000; 73 | } 74 | 75 | private: 76 | int64_t begin_nsec; 77 | int64_t total_nsec; 78 | }; 79 | 80 | } // namespace kedixa 81 | 82 | #endif // KEDIXA_TIMER_H 83 | -------------------------------------------------------------------------------- /include/kedixa/unsigned_bigint.h: -------------------------------------------------------------------------------- 1 | #ifndef KEDIXA_UNSIGNED_BIGINT_H 2 | #define KEDIXA_UNSIGNED_BIGINT_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace kedixa { 11 | 12 | namespace _k_help { 13 | 14 | template 15 | struct NPOW_OF_TEN 16 | { static const T value = NPOW_OF_TEN::value * 10; }; 17 | 18 | template 19 | struct NPOW_OF_TEN 20 | { static const T value = 1; }; 21 | 22 | } // namespace _k_help 23 | 24 | class unsigned_bigint { 25 | template 26 | using vector = std::vector; 27 | template 28 | using NPOW_OF_TEN = _k_help::NPOW_OF_TEN; 29 | 30 | public: 31 | using size_type = size_t; 32 | using uint_type = uint32_t; 33 | using int_type = int32_t; 34 | using ull_type = uint64_t; 35 | using llint_type = int64_t; 36 | 37 | static const uint_type UINT_TYPE_MAX = uint_type(-1); 38 | static const size_type UINT_LEN = sizeof(uint_type) * 8; 39 | static const size_type SUBSTR_LEN = UINT_LEN / 4; 40 | static const ull_type TENS_MASK = NPOW_OF_TEN::value; 41 | 42 | private: 43 | static const size_type MULTI_HINT = 130; 44 | static constexpr double TOSTR_HINT = 0.302 * UINT_LEN / SUBSTR_LEN; // 0.302 ~= log10(2) 45 | 46 | vector digits; 47 | void strip() noexcept; 48 | 49 | public: 50 | // constructors 51 | explicit 52 | unsigned_bigint(const uint_type number = 0 ); 53 | explicit 54 | unsigned_bigint(const vector& ); 55 | explicit 56 | unsigned_bigint(vector&& ); 57 | explicit 58 | unsigned_bigint(const std::string& ); 59 | explicit 60 | unsigned_bigint(const char* ); 61 | unsigned_bigint(const unsigned_bigint& ); 62 | unsigned_bigint(unsigned_bigint&& ); 63 | 64 | // assignment operators 65 | unsigned_bigint& operator= (const unsigned_bigint& ); 66 | unsigned_bigint& operator= (unsigned_bigint&& ); 67 | unsigned_bigint& operator+= (const uint_type ); 68 | unsigned_bigint& operator+= (const unsigned_bigint& ); 69 | unsigned_bigint& operator-= (const uint_type ); 70 | unsigned_bigint& operator-= (const unsigned_bigint& ); 71 | unsigned_bigint& operator*= (const uint_type ); 72 | unsigned_bigint& operator*= (const unsigned_bigint& ); 73 | unsigned_bigint& operator/= (const uint_type ); 74 | unsigned_bigint& operator/= (const unsigned_bigint& ); 75 | unsigned_bigint& operator%= (const uint_type ); 76 | unsigned_bigint& operator%= (const unsigned_bigint& ); 77 | unsigned_bigint& operator&= (const unsigned_bigint& ); 78 | unsigned_bigint& operator|= (const unsigned_bigint& ); 79 | unsigned_bigint& operator^= (const unsigned_bigint& ); 80 | unsigned_bigint& operator<<=(const size_type ); 81 | unsigned_bigint& operator>>=(const size_type)noexcept; 82 | 83 | // conversion operators 84 | explicit operator bool() const noexcept; 85 | explicit operator uint_type() const noexcept; 86 | explicit operator ull_type() const noexcept; 87 | 88 | // conversion functions 89 | uint_type to_uint() const; 90 | ull_type to_ull() const; 91 | long double to_ld() const; 92 | 93 | // arithmetic operators 94 | friend unsigned_bigint operator+ (const unsigned_bigint&, const unsigned_bigint& ); 95 | friend unsigned_bigint operator+ (const unsigned_bigint&, unsigned_bigint&& ); 96 | friend unsigned_bigint operator+ (unsigned_bigint&&, const unsigned_bigint& ); 97 | friend unsigned_bigint operator+ (unsigned_bigint&&, unsigned_bigint&& ); 98 | friend unsigned_bigint operator+ (const unsigned_bigint&, const uint_type ); 99 | friend unsigned_bigint operator+ (const uint_type, const unsigned_bigint& ); 100 | friend unsigned_bigint operator+ (unsigned_bigint&&, const uint_type ); 101 | friend unsigned_bigint operator+ (const uint_type, unsigned_bigint&& ); 102 | 103 | friend unsigned_bigint operator- (const unsigned_bigint&, const unsigned_bigint& ); 104 | friend unsigned_bigint operator- (const unsigned_bigint&, unsigned_bigint&& ); 105 | friend unsigned_bigint operator- (unsigned_bigint&&, const unsigned_bigint& ); 106 | friend unsigned_bigint operator- (unsigned_bigint&&, unsigned_bigint&& ); 107 | friend unsigned_bigint operator- (const unsigned_bigint&, const uint_type ); 108 | friend unsigned_bigint operator- (const uint_type, const unsigned_bigint& ); 109 | friend unsigned_bigint operator- (unsigned_bigint&&, const uint_type ); 110 | friend unsigned_bigint operator- (const uint_type, unsigned_bigint&& ); 111 | 112 | friend unsigned_bigint operator* (const unsigned_bigint&, const unsigned_bigint& ); 113 | friend unsigned_bigint operator* (const unsigned_bigint&, unsigned_bigint&& ); 114 | friend unsigned_bigint operator* (unsigned_bigint&&, const unsigned_bigint& ); 115 | friend unsigned_bigint operator* (unsigned_bigint&&, unsigned_bigint&& ); 116 | friend unsigned_bigint operator* (const unsigned_bigint&, const uint_type ); 117 | friend unsigned_bigint operator* (const uint_type, const unsigned_bigint& ); 118 | friend unsigned_bigint operator* (unsigned_bigint&&, const uint_type ); 119 | friend unsigned_bigint operator* (const uint_type, unsigned_bigint&& ); 120 | 121 | friend unsigned_bigint operator/ (const unsigned_bigint&, const unsigned_bigint& ); 122 | friend unsigned_bigint operator/ (const unsigned_bigint&, unsigned_bigint&& ); 123 | friend unsigned_bigint operator/ (unsigned_bigint&&, const unsigned_bigint& ); 124 | friend unsigned_bigint operator/ (unsigned_bigint&&, unsigned_bigint&& ); 125 | friend unsigned_bigint operator/ (const unsigned_bigint&, const uint_type ); 126 | friend unsigned_bigint operator/ (const uint_type, const unsigned_bigint& ); 127 | friend unsigned_bigint operator/ (unsigned_bigint&&, const uint_type ); 128 | friend unsigned_bigint operator/ (const uint_type, unsigned_bigint&& ); 129 | 130 | 131 | friend unsigned_bigint operator% (const unsigned_bigint&, const unsigned_bigint& ); 132 | friend unsigned_bigint operator% (const unsigned_bigint&, unsigned_bigint&& ); 133 | friend unsigned_bigint operator% (unsigned_bigint&&, const unsigned_bigint& ); 134 | friend unsigned_bigint operator% (unsigned_bigint&&, unsigned_bigint&& ); 135 | friend unsigned_bigint operator% (const unsigned_bigint&, const uint_type ); 136 | friend unsigned_bigint operator% (const uint_type, const unsigned_bigint& ); 137 | friend unsigned_bigint operator% (unsigned_bigint&&, const uint_type ); 138 | friend unsigned_bigint operator% (const uint_type, unsigned_bigint&& ); 139 | 140 | unsigned_bigint& operator++(); 141 | unsigned_bigint& operator--(); 142 | unsigned_bigint operator++(int); 143 | unsigned_bigint operator--(int); 144 | unsigned_bigint operator+ () const; 145 | unsigned_bigint operator- () const = delete; 146 | 147 | // bitwise operators 148 | friend unsigned_bigint operator<<(const unsigned_bigint&, size_type ); 149 | friend unsigned_bigint operator<<(unsigned_bigint&&, size_type ); 150 | friend unsigned_bigint operator>>(const unsigned_bigint&, size_type ); 151 | friend unsigned_bigint operator>>(unsigned_bigint&&, size_type ); 152 | friend unsigned_bigint operator& (const unsigned_bigint&, const unsigned_bigint& ); 153 | friend unsigned_bigint operator& (const unsigned_bigint&, unsigned_bigint&& ); 154 | friend unsigned_bigint operator& (unsigned_bigint&&, const unsigned_bigint& ); 155 | friend unsigned_bigint operator& (unsigned_bigint&&, unsigned_bigint&& ); 156 | friend unsigned_bigint operator| (const unsigned_bigint&, const unsigned_bigint& ); 157 | friend unsigned_bigint operator| (const unsigned_bigint&, unsigned_bigint&& ); 158 | friend unsigned_bigint operator| (unsigned_bigint&&, const unsigned_bigint& ); 159 | friend unsigned_bigint operator| (unsigned_bigint&&, unsigned_bigint&& ); 160 | friend unsigned_bigint operator^ (const unsigned_bigint&, const unsigned_bigint& ); 161 | friend unsigned_bigint operator^ (const unsigned_bigint&, unsigned_bigint&& ); 162 | friend unsigned_bigint operator^ (unsigned_bigint&&, const unsigned_bigint& ); 163 | friend unsigned_bigint operator^ (unsigned_bigint&&, unsigned_bigint&& ); 164 | 165 | // relational operators 166 | friend bool operator< (const unsigned_bigint&, const uint_type ) noexcept; 167 | friend bool operator< (const uint_type, const unsigned_bigint& ) noexcept; 168 | friend bool operator< (const unsigned_bigint&, const unsigned_bigint& ) noexcept; 169 | friend bool operator==(const unsigned_bigint&, const uint_type ) noexcept; 170 | friend bool operator==(const uint_type, const unsigned_bigint& ) noexcept; 171 | friend bool operator==(const unsigned_bigint&, const unsigned_bigint& ) noexcept; 172 | friend bool operator<=(const unsigned_bigint&, const uint_type ) noexcept; 173 | friend bool operator<=(const uint_type, const unsigned_bigint& ) noexcept; 174 | friend bool operator<=(const unsigned_bigint&, const unsigned_bigint& ) noexcept; 175 | friend bool operator> (const unsigned_bigint&, const uint_type ) noexcept; 176 | friend bool operator> (const uint_type, const unsigned_bigint& ) noexcept; 177 | friend bool operator> (const unsigned_bigint&, const unsigned_bigint& ) noexcept; 178 | friend bool operator>=(const unsigned_bigint&, const uint_type ) noexcept; 179 | friend bool operator>=(const uint_type, const unsigned_bigint& ) noexcept; 180 | friend bool operator>=(const unsigned_bigint&, const unsigned_bigint& ) noexcept; 181 | friend bool operator!=(const unsigned_bigint&, const uint_type ) noexcept; 182 | friend bool operator!=(const uint_type, const unsigned_bigint& ) noexcept; 183 | friend bool operator!=(const unsigned_bigint&, const unsigned_bigint& ) noexcept; 184 | 185 | // others 186 | int compare(const unsigned_bigint&) const noexcept; 187 | 188 | unsigned_bigint add(const unsigned_bigint& ) const; 189 | unsigned_bigint add(const uint_type ) const; 190 | unsigned_bigint& add_eq(const unsigned_bigint& ); 191 | unsigned_bigint& add_eq(const uint_type ); 192 | 193 | unsigned_bigint sub(const unsigned_bigint& ) const; 194 | unsigned_bigint sub(const uint_type ) const; 195 | unsigned_bigint& sub_eq(const unsigned_bigint& ); 196 | unsigned_bigint& sub_eq(const uint_type ); 197 | 198 | unsigned_bigint multi(const unsigned_bigint& ) const; 199 | unsigned_bigint multi(const uint_type ) const; 200 | unsigned_bigint& multi_eq(const unsigned_bigint& ); 201 | unsigned_bigint& multi_eq(const uint_type ); 202 | 203 | unsigned_bigint div(const unsigned_bigint& ) const; 204 | unsigned_bigint div(const uint_type ) const; 205 | unsigned_bigint& div_eq(const unsigned_bigint& ); 206 | unsigned_bigint& div_eq(const uint_type ); 207 | 208 | unsigned_bigint mod(const unsigned_bigint& ) const; 209 | unsigned_bigint mod(const uint_type ) const; 210 | unsigned_bigint& mod_eq(const unsigned_bigint& ); 211 | unsigned_bigint& mod_eq(const uint_type ); 212 | 213 | std::pair div_mod(const unsigned_bigint&) const; 214 | std::pair div_mod(const uint_type) const; 215 | 216 | void swap(unsigned_bigint&) noexcept; 217 | size_type size() const noexcept; 218 | std::string to_string(bool reverse = false) const; 219 | ~unsigned_bigint() noexcept; 220 | 221 | friend std::hash; 222 | }; // unsigned_bigint 223 | 224 | void swap(unsigned_bigint&, unsigned_bigint&) noexcept; 225 | 226 | } // namespace kedixa 227 | 228 | // specialize std::hash 229 | namespace std { 230 | template<> struct hash { 231 | size_t operator()(const kedixa::unsigned_bigint &ubigint) const { 232 | size_t hash_code = 0; 233 | auto h = std::hash(); 234 | 235 | for(auto &x : ubigint.digits) 236 | hash_code ^= h(x); 237 | 238 | return hash_code; 239 | } 240 | }; 241 | 242 | } // namespace std 243 | 244 | #endif // KEDIXA_UNSIGNED_BIGINT_H 245 | -------------------------------------------------------------------------------- /kedixa-config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | set(KEDIXA_VERSION "@kedixa_VERSION@") 4 | set_and_check(KEDIXA_INCLUDE_DIR "@PACKAGE_INCLUDE_DIR@") 5 | set_and_check(KEDIXA_LIBRARY_DIR "@PACKAGE_LIBRARY_DIR@") 6 | 7 | check_required_components("@LIBRARY_NAME@") 8 | set(KEDIXA_LIBRARIES "@LIBRARY_NAME@") 9 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | 3 | add_library(${KEDIXA_LIBRARY_NAME} STATIC 4 | bigint.cpp 5 | rational.cpp 6 | unsigned_bigint.cpp 7 | ) 8 | 9 | include_directories(${KEDIXA_LIBRARY_NAME} 10 | ${KEDIXA_INCLUDE_DIR} 11 | ) 12 | 13 | target_include_directories(${KEDIXA_LIBRARY_NAME} PUBLIC 14 | ${KEDIXA_INCLUDE_DIR} 15 | ) 16 | -------------------------------------------------------------------------------- /src/bigint.cpp: -------------------------------------------------------------------------------- 1 | #include "kedixa/bigint.h" 2 | 3 | #include 4 | #include 5 | 6 | namespace kedixa { 7 | 8 | // constructors 9 | bigint::bigint(const int_type number) 10 | { 11 | llint_type num = number; 12 | sign = (number < 0); 13 | ubig = unsigned_bigint(sign ? uint_type(-num) : uint_type(num)); 14 | } 15 | bigint::bigint(const unsigned_bigint &ubig, bool sign) 16 | { 17 | this->ubig = ubig; 18 | this->sign = sign; 19 | } 20 | bigint::bigint(unsigned_bigint &&ubig, bool sign) 21 | { 22 | this->ubig = std::move(ubig); 23 | this->sign = sign; 24 | } 25 | bigint::bigint(const std::string &str) 26 | { 27 | size_type len = str.length(); 28 | if(len == 0) 29 | { 30 | ubig = unsigned_bigint(0u); 31 | sign = false; 32 | } 33 | else if(str[0] == '+' || str[0] == '-') 34 | { 35 | ubig = unsigned_bigint(str.substr(1, len - 1)); 36 | sign = (str[0] == '-'); 37 | } 38 | else 39 | { 40 | ubig = unsigned_bigint(str); 41 | sign = false; 42 | } 43 | } 44 | bigint::bigint(const char *ch) 45 | : bigint(std::string(ch)) {} 46 | bigint::bigint(const bigint &big) 47 | { 48 | this->sign = big.sign; 49 | this->ubig = big.ubig; 50 | } 51 | bigint::bigint(bigint &&big) 52 | { 53 | this->sign = big.sign; 54 | this->ubig = std::move(big.ubig); 55 | } 56 | 57 | // assignment operators 58 | bigint& bigint::operator=(const bigint &big) 59 | { 60 | if(this != &big) 61 | { 62 | this->sign = big.sign; 63 | this->ubig = big.ubig; 64 | } 65 | return *this; 66 | } 67 | bigint& bigint::operator=(bigint &&big) 68 | { 69 | if(this != &big) 70 | { 71 | this->sign = big.sign; 72 | this->ubig = std::move(big.ubig); 73 | } 74 | return *this; 75 | } 76 | bigint& bigint::operator+=(const int_type number) 77 | { return this->add_eq(number); } 78 | bigint& bigint::operator+=(const bigint &big) 79 | { return this->add_eq(big); } 80 | bigint& bigint::operator-=(const int_type number) 81 | { return this->sub_eq(number); } 82 | bigint& bigint::operator-=(const bigint &big) 83 | { return this->sub_eq(big); } 84 | bigint& bigint::operator*=(const int_type number) 85 | { return this->multi_eq(number); } 86 | bigint& bigint::operator*=(const bigint &big) 87 | { return this->multi_eq(big); } 88 | bigint& bigint::operator/=(const int_type number) 89 | { return this->div_eq(number); } 90 | bigint& bigint::operator/=(const bigint &big) 91 | { return this->div_eq(big); } 92 | bigint& bigint::operator%=(const int_type number) 93 | { return this->mod_eq(number); } 94 | bigint& bigint::operator%=(const bigint &big) 95 | { return this->mod_eq(big); } 96 | 97 | // conversion operators 98 | bigint::operator bool() const noexcept 99 | { return *this != 0; } 100 | bigint::operator int_type() const noexcept 101 | { 102 | auto i = static_cast(this->ubig); 103 | int_type result = static_cast(i); 104 | if(this->sign) return -result; 105 | else return result; 106 | } 107 | bigint::operator llint_type() const noexcept 108 | { 109 | auto i = static_cast(this->ubig); 110 | llint_type result = static_cast(i); 111 | if(this->sign) return -result; 112 | else return result; 113 | } 114 | bigint::operator unsigned_bigint() const noexcept 115 | { return this->ubig; } 116 | 117 | // conversion functions 118 | bigint::int_type bigint::to_int() const 119 | { 120 | auto i = static_cast(*this); 121 | if(*this == bigint(std::to_string(i))) 122 | return i; 123 | else 124 | throw std::runtime_error("bigint too large to convert to int."); 125 | } 126 | bigint::llint_type bigint::to_ll() const 127 | { 128 | auto i = static_cast(*this); 129 | if(*this == bigint(std::to_string(i))) 130 | return i; 131 | else 132 | throw std::runtime_error("bigint too large to convert to long long."); 133 | } 134 | long double bigint::to_ld() const 135 | { 136 | auto d = this->ubig.to_ld(); 137 | if(this->sign) return -d; 138 | else return d; 139 | } 140 | unsigned_bigint bigint::to_ubigint() const 141 | { return this->ubig; } 142 | 143 | // arithmetic operators 144 | bigint operator+(const bigint &lhs, const bigint &rhs) 145 | { return std::move(lhs.add(rhs)); } 146 | bigint operator-(const bigint &lhs, const bigint &rhs) 147 | { return std::move(lhs.sub(rhs)); } 148 | bigint operator*(const bigint &lhs, const bigint &rhs) 149 | { return std::move(lhs.multi(rhs)); } 150 | bigint operator/(const bigint &lhs, const bigint &rhs) 151 | { return std::move(lhs.div(rhs)); } 152 | bigint operator%(const bigint &lhs, const bigint &rhs) 153 | { return std::move(lhs.mod(rhs)); } 154 | 155 | bigint& bigint::operator++() 156 | { 157 | int cmp = this->compare(bigint(-1)); 158 | if(cmp < 0) --this->ubig; 159 | else if(cmp > 0) ++this->ubig; 160 | else *this = bigint(0); 161 | return *this; 162 | } 163 | bigint& bigint::operator--() 164 | { 165 | int cmp = this->compare(bigint(0)); 166 | if(cmp > 0) --this->ubig; 167 | else if(cmp < 0) ++this->ubig; 168 | else *this = bigint(-1); 169 | return *this; 170 | } 171 | bigint bigint::operator++(int) 172 | { 173 | bigint tmp = *this; 174 | ++*this; 175 | return std::move(tmp); 176 | } 177 | bigint bigint::operator--(int) 178 | { 179 | bigint tmp = *this; 180 | --*this; 181 | return std::move(tmp); 182 | } 183 | bigint bigint::operator+ () const 184 | { return *this; } 185 | bigint bigint::operator- () const 186 | { 187 | bigint tmp = *this; 188 | tmp.opposite(); 189 | return std::move(tmp); 190 | } 191 | 192 | // bitwise operators 193 | bigint operator<<(const bigint &big, bigint::size_type sz) 194 | { 195 | bigint tmp = big; 196 | tmp.ubig <<= sz; 197 | return std::move(tmp); 198 | } 199 | bigint operator>>(const bigint &big, bigint::size_type sz) 200 | { 201 | if(sz == 0) return big; 202 | bigint tmp = big; 203 | if(tmp.sign == false) 204 | tmp.ubig >>= sz; 205 | // right shift for negative number 206 | else if(tmp.sign == true) 207 | { 208 | auto x = (unsigned_bigint(1u) << sz) - 1; 209 | x &= tmp.ubig; // lower sz bits of tmp.ubig 210 | tmp.ubig >>= sz; 211 | // if x is not 0, the answer should add by 1 212 | // for example, -9 >> 2 = -3, -8 >> 2 = -2 213 | if(x != unsigned_bigint(0u)) 214 | ++tmp.ubig; 215 | } 216 | return std::move(tmp); 217 | } 218 | 219 | // relational operators 220 | bool operator< (const bigint &lhs, const bigint &rhs) noexcept 221 | { return lhs.compare(rhs) < 0; } 222 | bool operator==(const bigint &lhs, const bigint &rhs) noexcept 223 | { return lhs.compare(rhs) == 0; } 224 | bool operator<=(const bigint &lhs, const bigint &rhs) noexcept 225 | { return !(rhs < lhs); } 226 | bool operator> (const bigint &lhs, const bigint &rhs) noexcept 227 | { return rhs < lhs; } 228 | bool operator>=(const bigint &lhs, const bigint &rhs) noexcept 229 | { return !(lhs < rhs); } 230 | bool operator!=(const bigint &lhs, const bigint &rhs) noexcept 231 | { return !(lhs == rhs); } 232 | 233 | // others 234 | int bigint::compare(const bigint &big) const noexcept 235 | { 236 | if(this->sign == big.sign) 237 | { 238 | int cmp = this->ubig.compare(big.ubig); 239 | if(this->sign == 0) return cmp; 240 | else return -cmp; 241 | } 242 | else if(this->sign == 0) return 1; 243 | else return -1; 244 | } 245 | 246 | bigint bigint::add(const bigint &big) const 247 | { 248 | bigint result; 249 | if(this->sign == big.sign) 250 | result = bigint(this->ubig + big.ubig, this->sign); 251 | else 252 | { 253 | int cmp = this->ubig.compare(big.ubig); 254 | if(cmp > 0) 255 | result = bigint(this->ubig - big.ubig, this->sign); 256 | else if(cmp < 0) 257 | result = bigint(big.ubig - this->ubig, !this->sign); 258 | else result = bigint(0); 259 | } 260 | return std::move(result); 261 | } 262 | bigint& bigint::add_eq(const bigint &big) 263 | { 264 | if(this->sign == big.sign) 265 | this->ubig += big.ubig; 266 | else 267 | { 268 | int cmp = this->ubig.compare(big.ubig); 269 | if(cmp > 0) 270 | this->ubig -= big.ubig; 271 | else if(cmp < 0) 272 | *this = bigint(big.ubig - this->ubig, !this->sign); 273 | else *this = bigint(0); 274 | } 275 | return *this; 276 | } 277 | bigint bigint::sub(const bigint &big) const 278 | { 279 | bigint result; 280 | if(this->sign != big.sign) 281 | result = bigint(this->ubig + big.ubig, this->sign); 282 | else 283 | { 284 | int cmp = this->ubig.compare(big.ubig); 285 | if(cmp > 0) 286 | result = bigint(this->ubig - big.ubig, this->sign); 287 | else if(cmp < 0) 288 | result = bigint(big.ubig - this->ubig, !this->sign); 289 | else result = bigint(0); 290 | } 291 | return std::move(result); 292 | } 293 | bigint& bigint::sub_eq(const bigint &big) 294 | { 295 | if(this->sign != big.sign) 296 | this->ubig += big.ubig; 297 | else 298 | { 299 | int cmp = this->ubig.compare(big.ubig); 300 | if(cmp > 0) 301 | this->ubig -= big.ubig; 302 | else if(cmp < 0) 303 | *this = bigint(big.ubig - this->ubig, !this->sign); 304 | else *this = bigint(0); 305 | } 306 | return *this; 307 | } 308 | bigint bigint::multi(const bigint &big) const 309 | { 310 | if(this->ubig == 0 || big.ubig == 0) return bigint(0); 311 | return bigint(this->ubig * big.ubig, this->sign ^ big.sign); 312 | } 313 | bigint& bigint::multi_eq(const bigint &big) 314 | { 315 | if(this->ubig == 0 || big.ubig == 0) *this = bigint(0); 316 | else this->ubig *= big.ubig, this->sign ^= big.sign; 317 | return *this; 318 | } 319 | bigint bigint::div(const bigint &big) const 320 | { return std::move(this->div_mod(big).first); } 321 | bigint& bigint::div_eq(const bigint &big) 322 | { return *this = this->div_mod(big).first; } 323 | bigint bigint::mod(const bigint &big) const 324 | { return std::move(this->div_mod(big).second); } 325 | bigint& bigint::mod_eq(const bigint &big) 326 | { return *this = this->div_mod(big).second; } 327 | 328 | std::pair bigint::div_mod(const bigint &big) const 329 | { 330 | auto result = this->ubig.div_mod(big.ubig); 331 | if(this->sign == big.sign) 332 | return std::make_pair(bigint(std::move(result.first)), 333 | bigint(std::move(result.second))); 334 | else 335 | { 336 | // if they have different sign, adjust the result as follow. 337 | // for example, -11/7 = -2 ... 3, and 11 / -7 = -2 ... -3 338 | // but 11 / 7 = 1 ... 4 339 | if(result.second != 0u) 340 | { 341 | ++result.first; 342 | result.second = big.ubig - result.second; 343 | return std::make_pair(bigint(std::move(result.first), 1), 344 | bigint(std::move(result.second), big.sign)); 345 | } 346 | else 347 | return std::make_pair(bigint(std::move(result.first), 1), 348 | bigint(0)); 349 | } 350 | } 351 | void bigint::opposite() noexcept 352 | { if(*this != bigint(0)) this->sign = !this->sign; } 353 | void bigint::swap(bigint &big) noexcept 354 | { 355 | std::swap(this->sign, big.sign); 356 | this->ubig.swap(big.ubig); 357 | } 358 | bigint::size_type bigint::size() const noexcept 359 | { return this->ubig.size(); } 360 | std::string bigint::to_string(bool reverse) const 361 | { 362 | std::string str = this->ubig.to_string(true); 363 | if(this->sign) str.push_back('-'); 364 | if(!reverse) 365 | { 366 | auto first = str.begin(), last = str.end(); 367 | while((first != last) && (first != --last)) 368 | std::iter_swap(first, last), ++first; 369 | } 370 | return std::move(str); 371 | } 372 | bigint::~bigint() noexcept 373 | { } 374 | 375 | // non-member function 376 | void swap(bigint &big1, bigint &big2) noexcept 377 | { 378 | big1.swap(big2); 379 | return; 380 | } 381 | 382 | } // namespace kedixa 383 | -------------------------------------------------------------------------------- /src/rational.cpp: -------------------------------------------------------------------------------- 1 | #include "kedixa/rational.h" 2 | 3 | #include 4 | 5 | namespace kedixa { 6 | 7 | // constructors 8 | rational::rational(const ubigint &n, const ubigint &d, bool sign) 9 | { 10 | // Each rational number must have only one representation, 11 | // avoid n/0, 2/4, -0/1, 4/2 ... 12 | this->num = n; 13 | this->den = d; 14 | this->sign = sign; 15 | this->reduce(); 16 | } 17 | rational::rational(ubigint &&n, ubigint &&d, bool sign) 18 | { 19 | this->num = std::move(n); 20 | this->den = std::move(d); 21 | this->sign = sign; 22 | this->reduce(); 23 | } 24 | rational::rational(const rational &rat) 25 | { 26 | this->num = rat.num; 27 | this->den = rat.den; 28 | this->sign = rat.sign; 29 | } 30 | rational::rational(rational &&rat) 31 | { 32 | this->num = std::move(rat.num); 33 | this->den = std::move(rat.den); 34 | this->sign = rat.sign; 35 | } 36 | 37 | // assignment operators 38 | rational& rational::operator= (const rational &rat) 39 | { 40 | if(this == &rat) return *this; 41 | this->num = rat.num; 42 | this->den = rat.den; 43 | this->sign = rat.sign; 44 | return *this; 45 | } 46 | rational& rational::operator= (rational &&rat) 47 | { 48 | if(this == &rat) return *this; 49 | this->num = std::move(rat.num); 50 | this->den = std::move(rat.den); 51 | this->sign = rat.sign; 52 | return *this; 53 | } 54 | rational& rational::operator+=(const rational &rat) 55 | { return this->add_eq(rat); } 56 | rational& rational::operator-=(const rational &rat) 57 | { return this->sub_eq(rat); } 58 | rational& rational::operator*=(const rational &rat) 59 | { return this->multi_eq(rat); } 60 | rational& rational::operator/=(const rational &rat) 61 | { return this->div_eq(rat); } 62 | 63 | // conversion operators 64 | rational::operator bool() const noexcept 65 | { return this->num != 0u; } 66 | 67 | // conversion functions 68 | long double rational::to_ld() const 69 | { 70 | long double n = this->num.to_ld(); 71 | long double d = this->den.to_ld(); 72 | return sign ? -n/d : n/d; 73 | } 74 | 75 | //arithmetic operators 76 | rational operator+ (const rational &lhs, const rational &rhs) 77 | { return lhs.add(rhs); } 78 | rational operator- (const rational &lhs, const rational &rhs) 79 | { return lhs.sub(rhs); } 80 | rational operator* (const rational &lhs, const rational &rhs) 81 | { return lhs.multi(rhs); } 82 | rational operator/ (const rational &lhs, const rational &rhs) 83 | { return lhs.div(rhs); } 84 | 85 | rational rational::operator+ () const 86 | { return *this; } 87 | rational rational::operator- () const 88 | { 89 | rational tmp = *this; 90 | tmp.opposite(); 91 | return tmp; 92 | } 93 | 94 | // relational operators 95 | bool operator< (const rational &lhs, const rational &rhs) 96 | { return lhs.compare(rhs) < 0; } 97 | bool operator==(const rational &lhs, const rational &rhs) noexcept 98 | { return lhs.sign==rhs.sign && lhs.num==rhs.num && lhs.den==rhs.den; } 99 | bool operator<=(const rational &lhs, const rational &rhs) 100 | { return !(rhs < lhs); } 101 | bool operator> (const rational &lhs, const rational &rhs) 102 | { return rhs < lhs; } 103 | bool operator>=(const rational &lhs, const rational &rhs) 104 | { return !(lhs < rhs); } 105 | bool operator!=(const rational &lhs, const rational &rhs) noexcept 106 | { return !(lhs == rhs); } 107 | 108 | // others 109 | int rational::compare(const rational &rat) const 110 | { 111 | int cmp; 112 | // same sign 113 | if(this->sign != rat.sign) 114 | cmp = (this->sign == false) ? 1 : -1; 115 | // different sign 116 | else 117 | { 118 | // same denominator 119 | if(this->den == rat.den) 120 | cmp = this->num.compare(rat.num); 121 | // different denominator 122 | else 123 | cmp = (this->num*rat.den).compare(this->den * rat.num); 124 | // -cmp for negative number 125 | if(this->sign) cmp = -cmp; 126 | } 127 | return cmp; 128 | } 129 | 130 | rational rational::add (const rational &rat) const 131 | { 132 | ubigint g = gcd(this->den, rat.den); // great common divisor 133 | ubigint ag = this->den / g, cg = rat.den / g; // den / gcd 134 | 135 | // using common method for fraction plus 136 | // b/a + d/c = (bc+ad)/(ac) = (bc/g + da/g)/(ac/g) 137 | rational result; 138 | const ubigint &b = this->num, &d = rat.num; 139 | result.den = ag * rat.den; 140 | if(this->sign == rat.sign) 141 | { 142 | result.num = b * cg + d * ag; 143 | result.sign = this->sign; 144 | } 145 | else 146 | { 147 | ubigint bcg = b * cg, dag = d * ag; 148 | int cmp = bcg.compare(dag); 149 | if(cmp >= 0) 150 | { 151 | result.num = std::move(bcg) - dag; 152 | result.sign = this->sign; 153 | } 154 | else 155 | { 156 | result.num = std::move(dag) - bcg; 157 | result.sign = !this->sign; 158 | } 159 | } 160 | result.reduce(); 161 | return result; 162 | } 163 | rational& rational::add_eq(const rational &rat) 164 | { return *this = this->add(rat); } 165 | rational rational::sub (const rational &rat) const 166 | { 167 | ubigint g = gcd(this->den, rat.den); // great common divisor 168 | ubigint ag = this->den / g, cg = rat.den / g; // den / gcd 169 | 170 | // using common method for fraction minus 171 | // b/a - d/c = (bc-ad)/(ac) = (bc/g + da/g)/(ac/g) 172 | rational result; 173 | const ubigint &b = this->num, &d = rat.num; 174 | result.den = ag * rat.den; 175 | if(this->sign == rat.sign) 176 | { 177 | ubigint bcg = b * cg, dag = d * ag; 178 | int cmp = bcg.compare(dag); 179 | if(cmp >= 0) 180 | { 181 | result = std::move(bcg) - dag; 182 | result.sign = this->sign; 183 | } 184 | else 185 | { 186 | result = std::move(dag) - bcg; 187 | result.sign = !this->sign; 188 | } 189 | } 190 | else 191 | { 192 | result.num = b * cg + d * ag; 193 | result.sign = this->sign; 194 | } 195 | result.reduce(); 196 | return result; 197 | } 198 | rational& rational::sub_eq(const rational &rat) 199 | { return *this = this->sub(rat); } 200 | rational rational::multi(const rational &rat) const 201 | { 202 | rational result; 203 | // special case 204 | if(this->num == ubigint(0u) || rat.num == ubigint(0u)) 205 | result = rational(); 206 | // common method for fraction multiply 207 | else 208 | { 209 | const ubigint &a = this->den, &b = this->num, &c = rat.den, &d = rat.num; 210 | ubigint g1 = gcd(a, d), g2 = gcd(c, b); 211 | result.num = (b/g2) * (d/g1); 212 | result.den = (a/g1) * (c/g2); 213 | result.sign= this->sign ^ rat.sign; 214 | } 215 | return result; 216 | } 217 | rational& rational::multi_eq(const rational &rat) 218 | { return *this = this->multi(rat); } 219 | rational rational::div(const rational &rat) const 220 | { 221 | rational result; 222 | if(this->num == ubigint(0u)) 223 | result = rational(); 224 | else if(rat.num == 0) 225 | throw std::runtime_error("kedixa::rational: divide by zero."); 226 | else 227 | { 228 | // b/a / d/c = b/a * c/d 229 | const ubigint &a = this->den, &b = this->num, &c = rat.den, &d = rat.num; 230 | ubigint g1 = gcd(a, c), g2 = gcd(d, b); 231 | result.num = (b/g2) * (c/g1); 232 | result.den = (a/g1) * (d/g2); 233 | result.sign = this->sign ^ rat.sign; 234 | } 235 | return result; 236 | } 237 | rational& rational::div_eq(const rational &rat) 238 | { return *this = this->div(rat); } 239 | 240 | rational::ubigint rational::get_num() const 241 | { return this->num; } 242 | rational::ubigint rational::get_den() const 243 | { return this->den; } 244 | bool rational::get_sign() const 245 | { return this->sign; } 246 | void rational::approximate(rational::size_type hint) 247 | { 248 | size_type sz = this->den.size(); 249 | if(sz == 1) return; 250 | if(hint == 0) hint = sz/2; 251 | else if(hint >= sz) hint = sz - 1; 252 | this->num >>= (hint * ubigint::UINT_LEN); 253 | this->den >>= (hint * ubigint::UINT_LEN); 254 | this->reduce(); 255 | return; 256 | } 257 | void rational::opposite() noexcept 258 | { 259 | if(this->num != ubigint(0u)) 260 | this->sign = !this->sign; 261 | return; 262 | } 263 | void rational::reciprocal() 264 | { 265 | if(this->num == 0) 266 | throw std::runtime_error("kedixa::rational: numerator is zero."); 267 | else this->num.swap(this->den); 268 | return; 269 | } 270 | void rational::swap(rational &rat) noexcept 271 | { 272 | this->num.swap(rat.num); 273 | this->den.swap(rat.den); 274 | std::swap(this->sign, rat.sign); 275 | return; 276 | } 277 | rational::size_type rational::num_size() const noexcept 278 | { return this->num.size(); } 279 | rational::size_type rational::den_size() const noexcept 280 | { return this->den.size(); } 281 | std::string rational::to_string(bool reverse) const 282 | { 283 | std::string str; 284 | if(this->den != ubigint(1u)) 285 | { 286 | str += this->den.to_string(true); 287 | str += '/'; 288 | } 289 | str += this->num.to_string(true); 290 | if(this->sign == true) str += '-'; 291 | if(!reverse) 292 | { 293 | auto first = str.begin(), last = str.end(); 294 | while((first != last) && (first != --last)) 295 | std::iter_swap(first, last), ++first; 296 | } 297 | return str; 298 | } 299 | std::string rational::to_decimal(rational::size_type digital_digits, bool reverse) const 300 | { 301 | auto qr = this->num.div_mod(this->den); 302 | std::string str; 303 | if(digital_digits > 0) 304 | { 305 | std::string s = "1" + std::string(digital_digits, '0'); 306 | str += (qr.second * ubigint(s) / this->den).to_string(true); 307 | str += std::string(digital_digits - str.length(), '0'); 308 | str += "."; 309 | } 310 | str += qr.first.to_string(true); 311 | if(this->sign && this->num != ubigint(0u)) 312 | str += "-"; 313 | if(!reverse) 314 | { 315 | auto first = str.begin(), last = str.end(); 316 | while((first != last) && (first != --last)) 317 | std::iter_swap(first, last), ++first; 318 | } 319 | return str; 320 | } 321 | rational::~rational() noexcept 322 | {} 323 | 324 | // private 325 | rational::ubigint rational::gcd(rational::ubigint x, rational::ubigint y) 326 | { 327 | if(x > y) x.swap(y); 328 | while(x > 0) 329 | { 330 | ubigint q = y % x; 331 | y = std::move(x); 332 | x = std::move(q); 333 | } 334 | return y; 335 | } 336 | void rational::reduce() 337 | { 338 | if(this->den == 0u) 339 | throw std::runtime_error("kedixa::rational: denominator is zero."); 340 | if(this->num == 0u) 341 | { 342 | this->sign = false; 343 | this->den = ubigint(1); 344 | } 345 | else 346 | { 347 | ubigint g = gcd(this->num, this->den); 348 | this->num /= g; 349 | this->den /= g; 350 | } 351 | return; 352 | } 353 | 354 | } // namespace kedixa 355 | -------------------------------------------------------------------------------- /src/unsigned_bigint.cpp: -------------------------------------------------------------------------------- 1 | #include "kedixa/unsigned_bigint.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace kedixa { 8 | 9 | // constructors 10 | unsigned_bigint::unsigned_bigint(const uint_type number) 11 | { digits.resize(1, number); } 12 | unsigned_bigint::unsigned_bigint(const vector &_digits) 13 | { 14 | if(_digits.empty()) digits.assign(1, uint_type(0)); 15 | else digits = _digits; 16 | this->strip(); 17 | } 18 | unsigned_bigint::unsigned_bigint(vector &&_digits) 19 | { 20 | if(_digits.empty()) digits.assign(1, uint_type(0)); 21 | else digits.swap(_digits); 22 | this->strip(); 23 | } 24 | unsigned_bigint::unsigned_bigint(const std::string& str) 25 | { 26 | if(str.empty()) 27 | { 28 | this->digits.assign(1, uint_type(0)); 29 | return; 30 | } 31 | 32 | // string to uint_type 33 | auto stouint = [&str](size_type first, size_type last) { 34 | uint_type result = 0; 35 | while(first != last) 36 | { 37 | result *= 10; 38 | result += str[first] - '0'; 39 | ++first; 40 | } 41 | return result; 42 | }; 43 | 44 | size_type len = str.length(); 45 | size_type pos = len % SUBSTR_LEN; 46 | if(pos == 0) pos = SUBSTR_LEN; 47 | 48 | unsigned_bigint tmp(stouint(0, pos)); 49 | for(; pos < len; pos += SUBSTR_LEN) 50 | { 51 | tmp *= TENS_MASK; 52 | tmp += uint_type(stouint(pos, pos + SUBSTR_LEN)); 53 | } 54 | this->digits.swap(tmp.digits); 55 | } 56 | unsigned_bigint::unsigned_bigint(const char *ch) 57 | : unsigned_bigint(std::string(ch)) { } 58 | unsigned_bigint::unsigned_bigint(const unsigned_bigint &ubigint) 59 | { this->digits = ubigint.digits; } 60 | unsigned_bigint::unsigned_bigint(unsigned_bigint &&ubigint) 61 | { this->digits.swap(ubigint.digits); } 62 | 63 | // assignment operators 64 | unsigned_bigint& unsigned_bigint::operator=(const unsigned_bigint &ubigint) 65 | { 66 | if(this != &ubigint) 67 | this->digits = ubigint.digits; 68 | return *this; 69 | } 70 | unsigned_bigint& unsigned_bigint::operator=(unsigned_bigint &&ubigint) 71 | { 72 | this->digits.swap(ubigint.digits); 73 | return *this; 74 | } 75 | 76 | unsigned_bigint& unsigned_bigint::operator+=(const uint_type number) 77 | { return this->add_eq(number); } 78 | unsigned_bigint& unsigned_bigint::operator+=(const unsigned_bigint &ubigint) 79 | { return this->add_eq(ubigint); } 80 | 81 | unsigned_bigint& unsigned_bigint::operator-=(const uint_type number) 82 | { return this->sub_eq(number); } 83 | unsigned_bigint& unsigned_bigint::operator-=(const unsigned_bigint &ubigint) 84 | { return this->sub_eq(ubigint); } 85 | 86 | unsigned_bigint& unsigned_bigint::operator*=(const uint_type number) 87 | { return this->multi_eq(number); } 88 | unsigned_bigint& unsigned_bigint::operator*=(const unsigned_bigint &ubigint) 89 | { return this->multi_eq(ubigint); } 90 | 91 | unsigned_bigint& unsigned_bigint::operator/=(const uint_type number) 92 | { return this->div_eq(number); } 93 | unsigned_bigint& unsigned_bigint::operator/=(const unsigned_bigint &ubigint) 94 | { return this->div_eq(ubigint); } 95 | 96 | unsigned_bigint& unsigned_bigint::operator%=(const uint_type number) 97 | { return this->mod_eq(number); } 98 | unsigned_bigint& unsigned_bigint::operator%=(const unsigned_bigint &ubigint) 99 | { return this->mod_eq(ubigint); } 100 | 101 | unsigned_bigint& unsigned_bigint::operator&=(const unsigned_bigint &ubigint) 102 | { 103 | auto &a = this->digits; 104 | const auto &b = ubigint.digits; 105 | if(a.size() > b.size()) a.resize(b.size()); 106 | for(size_type i = 0; i < a.size(); ++i) 107 | a[i] &= b[i]; 108 | this->strip(); 109 | return *this; 110 | } 111 | 112 | unsigned_bigint& unsigned_bigint::operator|=(const unsigned_bigint &ubigint) 113 | { 114 | auto &a = this->digits; 115 | const auto &b = ubigint.digits; 116 | if(a.size() < b.size()) a.resize(b.size(), 0); 117 | for(size_type i = 0; i < a.size(); ++i) 118 | a[i] |= b[i]; 119 | return *this; 120 | } 121 | 122 | unsigned_bigint& unsigned_bigint::operator^=(const unsigned_bigint &ubigint) 123 | { 124 | auto &a = this->digits; 125 | const auto &b = ubigint.digits; 126 | if(a.size() < b.size()) a.resize(b.size(), 0); 127 | for(size_type i = 0; i < a.size(); ++i) 128 | a[i] ^= b[i]; 129 | this->strip(); 130 | return *this; 131 | } 132 | 133 | unsigned_bigint& unsigned_bigint::operator<<=(const size_type k) 134 | { 135 | if(*this != 0) 136 | { 137 | vector &a = this->digits; 138 | size_type r = k % UINT_LEN; 139 | if(r != 0) 140 | { 141 | ull_type s = 0; 142 | for(size_type i = 0; i < a.size(); ++i) 143 | { 144 | s |= (ull_type(a[i]) << r); 145 | a[i] = uint_type(s); 146 | s >>= UINT_LEN; 147 | } 148 | if(s) a.push_back(uint_type(s)); 149 | } 150 | a.insert(a.begin(), k/UINT_LEN, 0); 151 | } 152 | return *this; 153 | } 154 | 155 | unsigned_bigint& unsigned_bigint::operator>>=(const size_type k) noexcept 156 | { 157 | vector &a = this->digits; 158 | if(k/UINT_LEN >= a.size()) a.assign({0}); 159 | else 160 | { 161 | a.erase(a.begin(), a.begin()+k/UINT_LEN); 162 | size_type r = k % UINT_LEN; 163 | if(r != 0) 164 | { 165 | ull_type s = 0; 166 | for(size_type i = a.size() - 1; i != (size_type) -1; --i) 167 | { 168 | s |= ull_type(a[i]); 169 | a[i] = uint_type(s >> r); 170 | s <<= UINT_LEN; 171 | } 172 | } 173 | this->strip(); 174 | } 175 | return *this; 176 | } 177 | 178 | // conversion operators 179 | unsigned_bigint::operator bool() const noexcept 180 | { return *this != 0; } 181 | unsigned_bigint::operator uint_type() const noexcept 182 | { return this->digits[0]; } 183 | unsigned_bigint::operator ull_type() const noexcept 184 | { 185 | if(this->digits.size() == 1) return ull_type(this->digits[0]); 186 | else return (ull_type(this->digits[1]) << UINT_LEN) | this->digits[0]; 187 | } 188 | 189 | // conversion functions 190 | unsigned_bigint::uint_type unsigned_bigint::to_uint() const 191 | { 192 | if(this->digits.size() > 1) 193 | throw std::runtime_error("unsigned_bigint too large to convert to uint."); 194 | return static_cast(*this); 195 | } 196 | unsigned_bigint::ull_type unsigned_bigint::to_ull() const 197 | { 198 | if(this->digits.size() > 2) 199 | throw std::runtime_error("unsigned_bigint too large to convert to ull."); 200 | return static_cast(*this); 201 | } 202 | long double unsigned_bigint::to_ld() const 203 | { 204 | long double d = 0; 205 | long double base = ull_type(1) << UINT_LEN; 206 | for(auto it = this->digits.crbegin(); it != this->digits.crend(); ++it) 207 | { 208 | d *= base; 209 | d += (long double)(*it); 210 | } 211 | if(std::isinf(d)) 212 | { 213 | throw std::runtime_error("unsigned_bigint too large to convert to long double."); 214 | return 0; 215 | } 216 | return d; 217 | } 218 | 219 | // arthmetic operators 220 | unsigned_bigint operator+ (const unsigned_bigint &lhs, const unsigned_bigint &rhs) 221 | { return std::move(lhs.add(rhs)); } 222 | unsigned_bigint operator+ (const unsigned_bigint &lhs, unsigned_bigint &&rhs) 223 | { return std::move(rhs.add_eq(lhs)); } 224 | unsigned_bigint operator+ (unsigned_bigint &&lhs, const unsigned_bigint &rhs) 225 | { return std::move(lhs.add_eq(rhs)); } 226 | unsigned_bigint operator+ (unsigned_bigint &&lhs, unsigned_bigint &&rhs) 227 | { return std::move(lhs.add_eq(rhs)); } 228 | unsigned_bigint operator+ (const unsigned_bigint &lhs, const unsigned_bigint::uint_type rhs) 229 | { return std::move(lhs.add(rhs)); } 230 | unsigned_bigint operator+ (const unsigned_bigint::uint_type lhs, const unsigned_bigint &rhs) 231 | { return std::move(rhs.add(lhs)); } 232 | unsigned_bigint operator+ (unsigned_bigint &&lhs, const unsigned_bigint::uint_type rhs) 233 | { return std::move(lhs.add_eq(rhs)); } 234 | unsigned_bigint operator+ (const unsigned_bigint::uint_type lhs, unsigned_bigint &&rhs) 235 | { return std::move(rhs.add_eq(lhs)); } 236 | 237 | unsigned_bigint operator- (const unsigned_bigint &lhs, const unsigned_bigint &rhs) 238 | { return std::move(lhs.sub(rhs)); } 239 | unsigned_bigint operator- (const unsigned_bigint &lhs, unsigned_bigint &&rhs) 240 | { return std::move(lhs.sub(rhs)); } 241 | unsigned_bigint operator- (unsigned_bigint &&lhs, const unsigned_bigint &rhs) 242 | { return std::move(lhs.sub_eq(rhs)); } 243 | unsigned_bigint operator- (unsigned_bigint &&lhs, unsigned_bigint &&rhs) 244 | { return std::move(lhs.sub_eq(rhs)); } 245 | unsigned_bigint operator- (const unsigned_bigint &lhs, const unsigned_bigint::uint_type rhs) 246 | { return std::move(lhs.sub(rhs)); } 247 | unsigned_bigint operator- (const unsigned_bigint::uint_type lhs, const unsigned_bigint &rhs) 248 | { return std::move(unsigned_bigint(lhs).sub_eq(rhs)); } 249 | unsigned_bigint operator- (unsigned_bigint &&lhs, const unsigned_bigint::uint_type rhs) 250 | { return std::move(lhs.sub_eq(rhs)); } 251 | unsigned_bigint operator- (const unsigned_bigint::uint_type lhs, unsigned_bigint &&rhs) 252 | { return std::move(unsigned_bigint(lhs).sub_eq(rhs)); } 253 | 254 | unsigned_bigint operator* (const unsigned_bigint &lhs, const unsigned_bigint &rhs) 255 | { return std::move(lhs.multi(rhs)); } 256 | unsigned_bigint operator* (const unsigned_bigint &lhs, unsigned_bigint &&rhs) 257 | { return std::move(rhs.multi_eq(lhs)); } 258 | unsigned_bigint operator* (unsigned_bigint &&lhs, const unsigned_bigint &rhs) 259 | { return std::move(lhs.multi_eq(rhs)); } 260 | unsigned_bigint operator* (unsigned_bigint &&lhs, unsigned_bigint &&rhs) 261 | { return std::move(lhs.multi_eq(rhs)); } 262 | unsigned_bigint operator* (const unsigned_bigint &lhs, const unsigned_bigint::uint_type rhs) 263 | { return std::move(lhs.multi(rhs)); } 264 | unsigned_bigint operator* (const unsigned_bigint::uint_type lhs, const unsigned_bigint &rhs) 265 | { return std::move(rhs.multi(lhs)); } 266 | unsigned_bigint operator* (unsigned_bigint &&lhs, const unsigned_bigint::uint_type rhs) 267 | { return std::move(lhs.multi_eq(rhs)); } 268 | unsigned_bigint operator* (const unsigned_bigint::uint_type lhs, unsigned_bigint &&rhs) 269 | { return std::move(rhs.multi_eq(lhs)); } 270 | 271 | unsigned_bigint operator/ (const unsigned_bigint &lhs, const unsigned_bigint &rhs) 272 | { return std::move(lhs.div(rhs)); } 273 | unsigned_bigint operator/ (const unsigned_bigint &lhs, unsigned_bigint &&rhs) 274 | { return std::move(lhs.div(rhs)); } 275 | unsigned_bigint operator/ (unsigned_bigint &&lhs, const unsigned_bigint &rhs) 276 | { return std::move(lhs.div_eq(rhs)); } 277 | unsigned_bigint operator/ (unsigned_bigint &&lhs, unsigned_bigint &&rhs) 278 | { return std::move(lhs.div_eq(rhs)); } 279 | unsigned_bigint operator/ (const unsigned_bigint &lhs, const unsigned_bigint::uint_type rhs) 280 | { return std::move(lhs.div(rhs)); } 281 | unsigned_bigint operator/ (const unsigned_bigint::uint_type lhs, const unsigned_bigint &rhs) 282 | { 283 | unsigned_bigint tmp(lhs); 284 | return std::move(tmp.div_eq(rhs)); 285 | } 286 | unsigned_bigint operator/ (unsigned_bigint &&lhs, const unsigned_bigint::uint_type rhs) 287 | { return std::move(lhs.div_eq(rhs)); } 288 | unsigned_bigint operator/ (const unsigned_bigint::uint_type lhs, unsigned_bigint &&rhs) 289 | { 290 | unsigned_bigint tmp(lhs); 291 | return std::move(tmp.div_eq(rhs)); 292 | } 293 | 294 | unsigned_bigint operator% (const unsigned_bigint &lhs, const unsigned_bigint &rhs) 295 | { return std::move(lhs.mod(rhs)); } 296 | unsigned_bigint operator% (const unsigned_bigint &lhs, unsigned_bigint &&rhs) 297 | { return std::move(lhs.mod(rhs)); } 298 | unsigned_bigint operator% (unsigned_bigint &&lhs, const unsigned_bigint &rhs) 299 | { return std::move(lhs.mod_eq(rhs)); } 300 | unsigned_bigint operator% (unsigned_bigint &&lhs, unsigned_bigint &&rhs) 301 | { return std::move(lhs.mod_eq(rhs)); } 302 | unsigned_bigint operator% (const unsigned_bigint &lhs, const unsigned_bigint::uint_type rhs) 303 | { return std::move(lhs.mod(rhs)); } 304 | unsigned_bigint operator% (const unsigned_bigint::uint_type lhs, const unsigned_bigint &rhs) 305 | { 306 | unsigned_bigint tmp(lhs); 307 | return std::move(tmp.mod_eq(rhs)); 308 | } 309 | unsigned_bigint operator% (unsigned_bigint &&lhs, const unsigned_bigint::uint_type rhs) 310 | { return std::move(lhs.mod_eq(rhs)); } 311 | unsigned_bigint operator% (const unsigned_bigint::uint_type lhs, unsigned_bigint &&rhs) 312 | { 313 | unsigned_bigint tmp(lhs); 314 | return std::move(tmp.mod_eq(rhs)); 315 | } 316 | 317 | unsigned_bigint& unsigned_bigint::operator++() 318 | { return *this += 1; } 319 | unsigned_bigint& unsigned_bigint::operator--() 320 | { return *this -= 1; } 321 | unsigned_bigint unsigned_bigint::operator++(int) 322 | { 323 | unsigned_bigint tmp = *this; 324 | ++*this; 325 | return std::move(tmp); 326 | } 327 | unsigned_bigint unsigned_bigint::operator--(int) 328 | { 329 | unsigned_bigint tmp = *this; 330 | --*this; 331 | return std::move(tmp); 332 | } 333 | unsigned_bigint unsigned_bigint::operator+ () const 334 | { 335 | unsigned_bigint tmp = *this; 336 | return std::move(tmp); 337 | } 338 | 339 | // bitwise operators 340 | unsigned_bigint operator<<(const unsigned_bigint &lhs, const unsigned_bigint::size_type k) 341 | { 342 | unsigned_bigint tmp = lhs; 343 | return std::move(tmp <<= k); 344 | } 345 | unsigned_bigint operator<<(unsigned_bigint &&lhs, const unsigned_bigint::size_type k) 346 | { return std::move(lhs <<= k); } 347 | unsigned_bigint operator>>(const unsigned_bigint &lhs, const unsigned_bigint::size_type k) 348 | { 349 | unsigned_bigint tmp = lhs; 350 | return std::move(tmp >>= k); 351 | } 352 | unsigned_bigint operator>>(unsigned_bigint &&lhs, const unsigned_bigint::size_type k) 353 | { return std::move(lhs >>= k); } 354 | 355 | 356 | unsigned_bigint operator& (const unsigned_bigint &lhs, const unsigned_bigint &rhs) 357 | { 358 | unsigned_bigint tmp = lhs; 359 | return std::move(tmp &= rhs); 360 | } 361 | unsigned_bigint operator& (const unsigned_bigint &lhs, unsigned_bigint &&rhs) 362 | { return std::move(rhs &= lhs); } 363 | unsigned_bigint operator& (unsigned_bigint &&lhs, const unsigned_bigint &rhs) 364 | { return std::move(lhs &= rhs); } 365 | unsigned_bigint operator& (unsigned_bigint &&lhs, unsigned_bigint &&rhs) 366 | { return std::move(lhs &= rhs); } 367 | 368 | unsigned_bigint operator| (const unsigned_bigint &lhs, const unsigned_bigint &rhs) 369 | { 370 | unsigned_bigint tmp = lhs; 371 | return std::move(tmp |= rhs); 372 | } 373 | unsigned_bigint operator| (const unsigned_bigint &lhs, unsigned_bigint &&rhs) 374 | { return std::move(rhs |= lhs); } 375 | unsigned_bigint operator| (unsigned_bigint &&lhs, const unsigned_bigint &rhs) 376 | { return std::move(lhs |= rhs); } 377 | unsigned_bigint operator| (unsigned_bigint &&lhs, unsigned_bigint &&rhs) 378 | { return std::move(lhs |= rhs); } 379 | 380 | unsigned_bigint operator^ (const unsigned_bigint &lhs, const unsigned_bigint &rhs) 381 | { 382 | unsigned_bigint tmp = lhs; 383 | return std::move(tmp ^= rhs); 384 | } 385 | unsigned_bigint operator^ (const unsigned_bigint &lhs, unsigned_bigint &&rhs) 386 | { return std::move(rhs ^= lhs); } 387 | unsigned_bigint operator^ (unsigned_bigint &&lhs, const unsigned_bigint &rhs) 388 | { return std::move(lhs ^= rhs); } 389 | unsigned_bigint operator^ (unsigned_bigint &&lhs, unsigned_bigint &&rhs) 390 | { return std::move(lhs ^= rhs); } 391 | 392 | // relational operators 393 | bool operator< (const unsigned_bigint &lhs, const unsigned_bigint::uint_type rhs) noexcept 394 | { return lhs.digits.size() <= 1 && lhs.digits[0] < rhs; } 395 | bool operator< (const unsigned_bigint::uint_type lhs, const unsigned_bigint &rhs) noexcept 396 | { return rhs.digits.size() > 1 || lhs < rhs.digits[0]; } 397 | bool operator< (const unsigned_bigint &lhs, const unsigned_bigint &rhs) noexcept 398 | { return lhs.compare(rhs) < 0; } 399 | 400 | bool operator==(const unsigned_bigint &lhs, const unsigned_bigint::uint_type rhs) noexcept 401 | { return lhs.digits.size() <= 1 && lhs.digits[0] == rhs; } 402 | bool operator==(const unsigned_bigint::uint_type lhs, const unsigned_bigint &rhs) noexcept 403 | { return rhs.digits.size() <= 1 && lhs == rhs.digits[0]; } 404 | bool operator==(const unsigned_bigint &lhs, const unsigned_bigint &rhs) noexcept 405 | { return lhs.compare(rhs) == 0; } 406 | 407 | bool operator<=(const unsigned_bigint &lhs, const unsigned_bigint::uint_type rhs) noexcept 408 | { return !(rhs < lhs); } 409 | bool operator<=(const unsigned_bigint::uint_type lhs, const unsigned_bigint &rhs) noexcept 410 | { return !(rhs < lhs); } 411 | bool operator<=(const unsigned_bigint &lhs, const unsigned_bigint &rhs) noexcept 412 | { return !(rhs < lhs); } 413 | 414 | bool operator> (const unsigned_bigint &lhs, const unsigned_bigint::uint_type rhs) noexcept 415 | { return rhs < lhs; } 416 | bool operator> (const unsigned_bigint::uint_type lhs, const unsigned_bigint &rhs) noexcept 417 | { return rhs < lhs; } 418 | bool operator> (const unsigned_bigint &lhs, const unsigned_bigint &rhs) noexcept 419 | { return rhs < lhs; } 420 | 421 | bool operator>=(const unsigned_bigint &lhs, const unsigned_bigint::uint_type rhs) noexcept 422 | { return !(lhs < rhs); } 423 | bool operator>=(const unsigned_bigint::uint_type lhs, const unsigned_bigint &rhs) noexcept 424 | { return !(lhs < rhs); } 425 | bool operator>=(const unsigned_bigint &lhs, const unsigned_bigint &rhs) noexcept 426 | { return !(lhs < rhs); } 427 | 428 | bool operator!=(const unsigned_bigint &lhs, const unsigned_bigint::uint_type rhs) noexcept 429 | { return !(lhs == rhs); } 430 | bool operator!=(const unsigned_bigint::uint_type lhs, const unsigned_bigint &rhs) noexcept 431 | { return !(lhs == rhs); } 432 | bool operator!=(const unsigned_bigint &lhs, const unsigned_bigint &rhs) noexcept 433 | { return !(lhs == rhs); } 434 | 435 | // others 436 | int unsigned_bigint::compare(const unsigned_bigint &ubigint) const noexcept 437 | { 438 | const auto &a = this->digits, &b = ubigint.digits; 439 | size_type lena = a.size(), lenb = b.size(); 440 | if(lena > lenb) return 1; 441 | else if(lena < lenb) return -1; 442 | for(size_type i = lena - 1; i != (size_type)-1; --i) 443 | if(a[i] != b[i]) return (a[i] < b[i]) ? -1 : 1; 444 | return 0; 445 | } 446 | 447 | unsigned_bigint 448 | unsigned_bigint::add(const unsigned_bigint &ubigint) const 449 | { 450 | const vector *pa, *pb; 451 | if(this->digits.size() > ubigint.digits.size()) 452 | pa = &(this->digits), pb = &(ubigint.digits); 453 | else pa = &(ubigint.digits), pb = &(this->digits); 454 | const vector &a = *pa, &b = *pb; 455 | size_type lena = a.size(), lenb = b.size(); 456 | vector c(lena); 457 | ull_type carry = 0; 458 | size_type i = 0; 459 | for(; i < lenb; ++i) 460 | { 461 | carry += a[i]; 462 | carry += b[i]; 463 | c[i] = uint_type(carry); 464 | carry >>= UINT_LEN; 465 | } 466 | for(; i < lena; ++i) 467 | { 468 | carry += a[i]; 469 | c[i] = uint_type(carry); 470 | carry >>= UINT_LEN; 471 | } 472 | if(carry) c.push_back(uint_type(carry)); 473 | return std::move(unsigned_bigint(std::move(c))); 474 | } 475 | unsigned_bigint 476 | unsigned_bigint::add(const uint_type number) const 477 | { 478 | unsigned_bigint tmp = *this; 479 | tmp.add_eq(number); 480 | return std::move(tmp); 481 | } 482 | unsigned_bigint& 483 | unsigned_bigint::add_eq(const unsigned_bigint &ubigint) 484 | { 485 | size_type lena = this->digits.size(), lenb = ubigint.digits.size(); 486 | if(lena < lenb) this->digits.resize(lenb, 0), lena = lenb; 487 | 488 | ull_type carry = 0; 489 | vector &a = this->digits; 490 | const vector &b = ubigint.digits; 491 | size_type i = 0; 492 | for(; i < lenb; ++i) 493 | { 494 | carry += ull_type(a[i]) + ull_type(b[i]); 495 | a[i] = uint_type(carry); 496 | carry >>= UINT_LEN; 497 | } 498 | for(; carry && i < lena; ++i) 499 | { 500 | if(a[i]==UINT_TYPE_MAX) a[i] = 0; 501 | else ++a[i], carry = 0; 502 | } 503 | if(carry) a.push_back(uint_type(carry)); 504 | return *this; 505 | } 506 | unsigned_bigint& 507 | unsigned_bigint::add_eq(const uint_type number) 508 | { 509 | vector &a = this->digits; 510 | ull_type carry = ull_type(number) + ull_type(a[0]); 511 | a[0] = uint_type(carry); 512 | carry >>= UINT_LEN; 513 | for(size_type i = 1; carry && i < a.size(); ++i) 514 | { 515 | if(a[i]==UINT_TYPE_MAX) a[i] = 0; 516 | else ++a[i], carry = 0; 517 | } 518 | if(carry) a.push_back(uint_type(carry)); 519 | return *this; 520 | } 521 | 522 | unsigned_bigint 523 | unsigned_bigint::sub(const unsigned_bigint &ubigint) const 524 | { 525 | unsigned_bigint tmp = *this; 526 | tmp.sub_eq(ubigint); 527 | return std::move(tmp); 528 | } 529 | unsigned_bigint 530 | unsigned_bigint::sub(const uint_type number) const 531 | { 532 | unsigned_bigint tmp = *this; 533 | tmp.sub_eq(number); 534 | return std::move(tmp); 535 | } 536 | unsigned_bigint& 537 | unsigned_bigint::sub_eq(const unsigned_bigint &ubigint) 538 | { 539 | size_type len1 = this->digits.size(), len2 = ubigint.digits.size(); 540 | if(len1 < len2) 541 | throw std::underflow_error("unsigned_bigint:: subtraction underflow."); 542 | vector &a = this->digits; 543 | const vector &b = ubigint.digits; 544 | 545 | llint_type x = 0; 546 | size_type i = 0; 547 | for(; i < len2; ++i) 548 | { 549 | x += a[i]; 550 | x -= b[i]; 551 | a[i] = uint_type(x); 552 | x >>= UINT_LEN; 553 | } 554 | bool borrow = 0; 555 | if(x < 0) borrow = true; 556 | for(; borrow && i < len1; ++i) 557 | { 558 | if(a[i] == 0) a[i] = UINT_TYPE_MAX; 559 | else --a[i], borrow = false; 560 | } 561 | if(borrow) 562 | throw std::underflow_error("unsigned_bigint:: subtraction underflow."); 563 | this->strip(); 564 | return *this; 565 | } 566 | unsigned_bigint& 567 | unsigned_bigint::sub_eq(const uint_type number) 568 | { 569 | vector &a = this->digits; 570 | llint_type x = llint_type(a[0]); 571 | x -= llint_type(number); 572 | bool borrow = false; 573 | a[0] = uint_type(x); 574 | if(x < 0) borrow = true; 575 | for(size_type i = 0; borrow && i < a.size(); ++i) 576 | { 577 | if(a[i] == 0) a[i] = UINT_TYPE_MAX; 578 | else --a[i], borrow = false; 579 | } 580 | if(borrow) 581 | throw std::underflow_error("unsigned_bigint:: subtraction underflow."); 582 | this->strip(); 583 | return *this; 584 | } 585 | 586 | unsigned_bigint 587 | unsigned_bigint::multi(const unsigned_bigint &ubigint) const 588 | { 589 | // special case 590 | if(*this == 0 || ubigint == 0) return unsigned_bigint(uint_type(0)); 591 | if(*this == 1) return ubigint; 592 | if(ubigint == 1) return *this; 593 | // special end 594 | 595 | const vector &a = this->digits, &b = ubigint.digits; 596 | size_type lena = a.size(), lenb = b.size(); 597 | // if both a and b are long enough, 598 | // use divide and conquer algorithm 599 | if(lena > MULTI_HINT && lenb > MULTI_HINT) 600 | { 601 | unsigned_bigint a1, a2, b1, b2; 602 | vector &va1 = a1.digits, &va2 = a2.digits, 603 | &vb1 = b1.digits, &vb2 = b2.digits; 604 | size_type len_max = std::max(lena, lenb); 605 | size_type m = len_max / 2; 606 | 607 | // divide a and b to two parts 608 | // lower m digits, and higher (lenx - m) digits 609 | va2.assign(a.begin(), a.begin() + std::min(m, lena)); 610 | if(lena > m) va1.assign(a.begin() + m, a.end()); 611 | else va1.assign(1, uint_type(0)); 612 | vb2.assign(b.begin(), b.begin() + std::min(m, lenb)); 613 | if(lenb > m) vb1.assign(b.begin() + m, b.end()); 614 | else vb1.assign(1, uint_type(0)); 615 | // conquer (x = unsigned_bigint(1u) << (m*UINT_LEN)) 616 | // (a1*x + a2)*(b1*x + b2) 617 | // = a1*b1*x^2 + (a1*b2 + a2*b1)*x + a2*b2 618 | // = a1*b1*x^2 + ((a1+a2)*(b1+b2)-a1*b1-a2*b2)*x + a2*b2 619 | unsigned_bigint a1b1 = a1 * b1, a2b2 = a2 * b2; 620 | unsigned_bigint a1b2_a2b1 = (a1 + a2)*(b1 + b2) - a1b1 - a2b2; 621 | a1b1 <<= (m * 2 * UINT_LEN); 622 | a1b2_a2b1 <<= (m * UINT_LEN); 623 | return std::move(std::move(a1b1) + a1b2_a2b1 + a2b2); 624 | } 625 | // else if they are not long 626 | // use ordinary method 627 | vector result(lena + lenb, 0); 628 | // multi b[0] 629 | ull_type x = ull_type(b[0]), y = 0; 630 | if(x != 0) 631 | { 632 | for(size_type j = 0; j < lena; ++j) 633 | { 634 | y += x * a[j]; 635 | result[j] = uint_type(y); 636 | y >>= UINT_LEN; 637 | } 638 | result[lena] = uint_type(y); // carry 639 | } 640 | // multi b[1...] 641 | for(size_type i = 1; i < lenb; ++i) 642 | { 643 | x = ull_type(b[i]), y = 0; 644 | if(x == 0) continue; 645 | size_type j, k; 646 | for(j = 0, k = i; j < lena; ++j, ++k) 647 | { 648 | y += x * a[j] + result[k]; 649 | result[k] = uint_type(y); 650 | y >>= UINT_LEN; 651 | } 652 | result[k] = uint_type(y); 653 | } 654 | unsigned_bigint tmp(std::move(result)); 655 | return std::move(tmp); 656 | } 657 | unsigned_bigint 658 | unsigned_bigint::multi(const uint_type number) const 659 | { 660 | if(number == 0) return unsigned_bigint(uint_type(0)); 661 | if(number == 1) return *this; 662 | const vector &a = this->digits; 663 | vector c(a.size()); 664 | ull_type x = ull_type(number), y = 0; 665 | for(size_type i = 0; i < a.size(); ++i) 666 | { 667 | y += x * a[i]; 668 | c[i] = uint_type(y); 669 | y >>= UINT_LEN; 670 | } 671 | if(y) c.push_back(uint_type(y)); 672 | return unsigned_bigint(std::move(c)); 673 | } 674 | unsigned_bigint& 675 | unsigned_bigint::multi_eq(const unsigned_bigint &ubigint) 676 | { 677 | *this = this->multi(ubigint); 678 | return *this; 679 | } 680 | unsigned_bigint& 681 | unsigned_bigint::multi_eq(const uint_type number) 682 | { 683 | if(number == 0) 684 | { 685 | this->digits.assign(1, uint_type(0)); 686 | return *this; 687 | } 688 | if(number == 1) return *this; 689 | vector &a = this->digits; 690 | ull_type x = ull_type(number), y = 0; 691 | for(size_type i = 0; i < a.size(); ++i) 692 | { 693 | y += x * a[i]; 694 | a[i] = uint_type(y); 695 | y >>= UINT_LEN; 696 | } 697 | if(y) a.push_back(uint_type(y)); 698 | return *this; 699 | } 700 | 701 | unsigned_bigint 702 | unsigned_bigint::div(const unsigned_bigint &ubigint) const 703 | { return std::move((this->div_mod(ubigint)).first); } 704 | unsigned_bigint 705 | unsigned_bigint::div(const uint_type number) const 706 | { return std::move((this->div_mod(number)).first); } 707 | unsigned_bigint& 708 | unsigned_bigint::div_eq(const unsigned_bigint &ubigint) 709 | { 710 | *this = std::move((this->div_mod(ubigint)).first); 711 | return *this; 712 | } 713 | unsigned_bigint& 714 | unsigned_bigint::div_eq(const uint_type number) 715 | { 716 | if(number == 0) 717 | throw std::runtime_error("unsigned_bigint: divide by zero."); 718 | if(number == 1) 719 | return *this; 720 | vector &a = this->digits; 721 | ull_type x = ull_type(number), y = 0; 722 | size_type i = a.size() - 1; 723 | for(; i != (size_type)-1; --i) 724 | { 725 | y <<= UINT_LEN; 726 | y += a[i]; 727 | a[i] = uint_type(y/x); 728 | y %= x; 729 | } 730 | this->strip(); 731 | return *this; 732 | } 733 | 734 | unsigned_bigint 735 | unsigned_bigint::mod(const unsigned_bigint &ubigint) const 736 | { return std::move((this->div_mod(ubigint)).second); } 737 | unsigned_bigint 738 | unsigned_bigint::mod(const uint_type number) const 739 | { return std::move((this->div_mod(number)).second); } 740 | unsigned_bigint& 741 | unsigned_bigint::mod_eq(const unsigned_bigint &ubigint) 742 | { 743 | *this = std::move((this->div_mod(ubigint)).second); 744 | return *this; 745 | } 746 | unsigned_bigint& 747 | unsigned_bigint::mod_eq(const uint_type number) 748 | { 749 | if(number == 0) 750 | throw std::runtime_error("unsigned_bigint: divide by zero."); 751 | if(number == 1) 752 | return (*this = unsigned_bigint(uint_type(0))); 753 | vector &a = this->digits; 754 | ull_type x = ull_type(number), y = 0; 755 | size_type i = a.size() - 1; 756 | for(; i != (size_type)-1; --i) 757 | { 758 | y <<= UINT_LEN; 759 | y += a[i]; 760 | a[i] = uint_type(y/x); 761 | y %= x; 762 | } 763 | *this = unsigned_bigint(y); 764 | return *this; 765 | } 766 | 767 | std::pair 768 | unsigned_bigint::div_mod(const unsigned_bigint &ubigint) const 769 | { 770 | if(ubigint.digits.size() == 1) 771 | return this->div_mod(ubigint.digits[0]); 772 | // dividend less than divisor 773 | if(*this < ubigint) 774 | return std::make_pair(unsigned_bigint(uint_type(0)), unsigned_bigint(*this)); 775 | 776 | // implement the algorithm in Knuth[The Art of Computer Programming] 777 | unsigned_bigint dividend = *this, divisor = ubigint, rem; 778 | vector q; // save the quot 779 | // 1. normalize 780 | ull_type base = ull_type(1) << UINT_LEN; 781 | size_type lshift = 0; 782 | uint_type back = divisor.digits.back(); 783 | while(back < base/2) back<<=1, ++lshift; 784 | dividend <<= lshift, divisor <<= lshift; 785 | vector &a = dividend.digits; 786 | const vector &b = divisor.digits; 787 | size_type sz_b = b.size(); // size of divisor 788 | a.push_back(uint_type(0)); // for u0 789 | 790 | // 2. loop 791 | const uint_type &v1 = b[sz_b-1], &v2 = b[sz_b-2]; 792 | q.resize(a.size() - b.size()); 793 | for(size_type i = q.size() - 1; i != (size_type)-1; --i) 794 | { 795 | // get the estimated value of q 796 | ull_type qh; 797 | uint_type &u0 = a[i+sz_b], &u1 = a[i+sz_b-1], &u2 = a[i+sz_b-2]; 798 | qh = (u0 * base + u1) / v1; 799 | if(qh * v2 > base * (u0 * base + u1 - qh * v1) + u2) --qh; 800 | 801 | // multi and subtract 802 | llint_type borrow = 0; 803 | ull_type carry = 0; 804 | for(size_type j = 0; j < sz_b; ++j) 805 | { 806 | carry += qh * b[j]; 807 | borrow += a[i+j]; 808 | borrow -= uint_type(carry); 809 | a[i+j] = uint_type(borrow); 810 | borrow >>= UINT_LEN; 811 | carry >>= UINT_LEN; 812 | } 813 | borrow += a[i+sz_b]; 814 | borrow -= carry; 815 | a[i+sz_b] = uint_type(borrow); 816 | borrow >>= UINT_LEN; 817 | while(borrow < 0) 818 | { 819 | // add divisor back to dividend 820 | assert(borrow==-1); 821 | carry = 0; 822 | for(size_type j = 0; j < sz_b; ++j) 823 | { 824 | carry += a[i+j]; 825 | carry += b[j]; 826 | a[i+j] = uint_type(carry); 827 | carry >>= UINT_LEN; 828 | } 829 | carry += a[i+sz_b]; 830 | a[i+sz_b] = uint_type(carry); 831 | carry >>= UINT_LEN; 832 | borrow += carry; 833 | --qh; // don't forget 834 | } 835 | assert(borrow == 0); 836 | q[i] = uint_type(qh); 837 | 838 | } 839 | // 3. get quotient and real remainder 840 | unsigned_bigint quotient(std::move(q)); 841 | dividend.strip(); 842 | dividend >>= lshift; 843 | return std::make_pair(std::move(quotient), std::move(dividend)); 844 | } 845 | std::pair 846 | unsigned_bigint::div_mod(const uint_type number) const 847 | { 848 | if(number == 0) 849 | throw std::runtime_error("unsigned_bigint: divide by zero."); 850 | if(number == 1) 851 | return std::make_pair(unsigned_bigint(*this), unsigned_bigint(uint_type(0))); 852 | unsigned_bigint tmp = *this; 853 | vector &a = tmp.digits; 854 | ull_type x = ull_type(number), y = 0; 855 | size_type i = a.size() - 1; 856 | for(; i != (size_type)-1; --i) 857 | { 858 | y <<= UINT_LEN; 859 | y += a[i]; 860 | a[i] = uint_type(y/x); 861 | y %= x; 862 | } 863 | tmp.strip(); 864 | return std::make_pair(std::move(tmp), unsigned_bigint(uint_type(y))); 865 | } 866 | 867 | void unsigned_bigint::swap(unsigned_bigint &ubigint) noexcept 868 | { this->digits.swap(ubigint.digits); } 869 | 870 | std::string unsigned_bigint::to_string(bool reverse) const 871 | { 872 | vector v; 873 | const vector a = this->digits; 874 | v.reserve(a.size() * TOSTR_HINT); // roughly allocate memory 875 | ull_type y; 876 | for(size_type i = a.size() - 1; i != size_type(-1); --i) 877 | { 878 | uint_type x = a[i]; 879 | for(size_type j = 0; j < v.size(); ++j) 880 | { 881 | y = (ull_type(v[j]) << UINT_LEN) | x; 882 | x = uint_type(y / TENS_MASK); 883 | v[j] = uint_type(y % TENS_MASK); 884 | } 885 | while(x) 886 | { 887 | v.push_back(x % TENS_MASK); 888 | x /= TENS_MASK; 889 | } 890 | } 891 | std::string result; 892 | result.reserve(v.size() * SUBSTR_LEN); 893 | // If v.size > 1, add possible leading zeros to v[0..size-2] 894 | if(v.size() > 1) 895 | { 896 | for(size_type i = 0; i < v.size() - 1; ++i) 897 | { 898 | for(size_type j = 0; j < SUBSTR_LEN; ++j) 899 | result.push_back(v[i]%10 + '0'), v[i] /= 10; 900 | } 901 | } 902 | // But the last number in v don't need to 903 | auto &back = v.back(); 904 | while(back) 905 | { 906 | result.push_back(back%10 + '0'); 907 | back /= 10; 908 | } 909 | if(result.size() == 0) result.push_back('0'); 910 | 911 | // the result itself is reversed, so if reverse is false, 912 | // we reverse the result. 913 | if(!reverse) 914 | { 915 | auto first = result.begin(), last = result.end(); 916 | while((first != last) && (first != --last)) 917 | std::iter_swap(first, last), ++first; 918 | } 919 | return std::move(result); 920 | } 921 | 922 | unsigned_bigint::size_type unsigned_bigint::size() const noexcept 923 | { return digits.size(); } 924 | 925 | unsigned_bigint::~unsigned_bigint() noexcept 926 | { } 927 | 928 | // private: 929 | void unsigned_bigint::strip() noexcept 930 | { 931 | vector &a = this->digits; 932 | size_type sz = a.size() - 1; 933 | while(sz > 0 && a[sz] == 0) --sz; 934 | a.resize(sz + 1); 935 | return; 936 | } 937 | 938 | // non-member function 939 | void swap(unsigned_bigint &lhs, unsigned_bigint &rhs) noexcept 940 | { lhs.swap(rhs); } 941 | 942 | } // namespace kedixa 943 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | 3 | project( 4 | kedixa-test 5 | LANGUAGES CXX 6 | ) 7 | 8 | find_package(kedixa REQUIRED) 9 | find_package(Threads REQUIRED) 10 | 11 | include_directories(${KEDIXA_INCLUDE_DIR}) 12 | link_directories(${KEDIXA_LIBRARY_DIR}) 13 | 14 | set(TEST_TARGETS 15 | test_bigint 16 | test_multiarray 17 | test_rational 18 | test_timer 19 | test_unsigned_bigint 20 | ) 21 | 22 | set(CMAKE_BUILD_TYPE Debug) 23 | 24 | foreach(TARGET ${TEST_TARGETS}) 25 | add_executable( 26 | ${TARGET} 27 | ${TARGET}.cpp 28 | ) 29 | 30 | target_link_libraries( 31 | ${TARGET} 32 | ${KEDIXA_LIBRARIES} 33 | Threads::Threads 34 | ) 35 | endforeach() 36 | -------------------------------------------------------------------------------- /test/test_bigint.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "kedixa/bigint.h" 9 | 10 | using namespace std; 11 | using bigint = kedixa::bigint; 12 | 13 | bigint zero, one(1), ten(10), neg_one(-1), neg_ten(-10); 14 | bigint three(3), neg_three(-3); 15 | bigint int_max(2147483647), int_min(-2147483648); 16 | random_device rd; 17 | 18 | void check(); 19 | 20 | int main() 21 | { 22 | check(); 23 | return 0; 24 | } 25 | 26 | void check_to_string() 27 | { 28 | assert(zero.to_string() == "0"); 29 | assert(three.to_string() == "3"); 30 | assert(neg_three.to_string() == "-3"); 31 | assert(int_max.to_string() == "2147483647"); 32 | assert(int_min.to_string() == "-2147483648"); 33 | string s = "-2347298572398475918743982758937429576298437529834"; 34 | assert(bigint(s).to_string() == s); 35 | } 36 | 37 | void check_relation() 38 | { 39 | assert(zero == zero); 40 | assert(zero < one); 41 | assert(neg_one < one); 42 | assert(neg_one > neg_ten); 43 | assert(int_max != int_min); 44 | assert(three <= three); 45 | assert(ten >= int_min); 46 | } 47 | 48 | void check_add_sub() 49 | { 50 | assert(zero + zero == zero); 51 | assert(three + neg_three == zero); 52 | assert(int_max + int_min == neg_one); 53 | assert(three - neg_three == 6); 54 | bigint b1 = neg_one; 55 | assert(++b1 == zero); 56 | assert(--b1 == neg_one); 57 | assert(--b1 == -2); 58 | b1 = zero; 59 | assert(++b1 == one); 60 | } 61 | 62 | void check_multi_div() 63 | { 64 | assert(neg_one * zero == zero); 65 | assert(zero * ten == 0); 66 | assert(ten * neg_three == -30); 67 | assert(neg_three * neg_one == three); 68 | assert(ten / three == three); 69 | assert(ten % three == one); 70 | assert(neg_ten / neg_one == ten); 71 | assert(neg_ten % neg_one == zero); 72 | assert(ten / neg_three == -4); 73 | assert(ten % neg_three == -2); 74 | assert(int_min / neg_one == int_max + 1); 75 | } 76 | 77 | void check_hash() 78 | { 79 | unordered_set st; 80 | st.insert(zero); 81 | st.insert(neg_one); 82 | st.insert(three); 83 | st.insert(neg_ten); 84 | st.insert(int_max); 85 | assert(st.find(zero) != st.end()); 86 | } 87 | 88 | void check_convert() 89 | { 90 | assert(neg_one.to_int() == -1); 91 | assert(int_max.to_int() == 2147483647); 92 | assert(int_min.to_int() == -2147483648); 93 | long double d = int_min.to_ld(); 94 | static_cast(d); 95 | assert(neg_one.to_ubigint() == 1u); 96 | } 97 | 98 | void check_others() 99 | { 100 | assert((one << 4) == 16); 101 | assert((neg_one << 4) == -16); 102 | assert((neg_ten >> 12) == neg_one); 103 | assert((ten >> 12) == zero); 104 | assert(bigint(-7) >> 1 == -4); 105 | assert(bigint(-9) >> 2 == -3); 106 | } 107 | 108 | void check() 109 | { 110 | check_to_string(); 111 | check_relation(); 112 | check_add_sub(); 113 | check_multi_div(); 114 | check_hash(); 115 | check_convert(); 116 | check_others(); 117 | } 118 | -------------------------------------------------------------------------------- /test/test_multiarray.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * test_multiarray.cpp - Test multiarray. 3 | * 4 | * Copyright (c) 2016 kedixa(kedixa@outlook.com) 5 | * 6 | */ 7 | #include 8 | #include 9 | 10 | #include "kedixa/multiarray.h" 11 | 12 | using namespace std; 13 | 14 | int count_A = 0; 15 | class A{ 16 | public: 17 | double d; 18 | A(double _d = 0.0) 19 | { 20 | d = _d; 21 | ++count_A; 22 | } 23 | ~A() 24 | { --count_A; } 25 | }; 26 | 27 | template 28 | using int_array = kedixa::multiarray; 29 | template 30 | using A_array = kedixa::multiarray; 31 | 32 | void test_int() 33 | { 34 | int_array<2> arr(3, 4); 35 | for(int i = 0; i < 3; i++) 36 | for(int j = 0; j < 4; j++) 37 | arr[i][j] = i + j; 38 | assert(arr.size() == 3); 39 | assert(arr.dimension() == 2); 40 | 41 | auto &arr_ref = arr[0]; 42 | assert(arr_ref.dimension() == 1); 43 | 44 | for(size_t i = 0; i < arr.size(); i++) 45 | assert(arr[i].size() == 4); 46 | for(size_t i = 0; i < arr.size(); ++i) 47 | for(size_t j = 0; j < arr[i].size(); ++j) 48 | assert(arr[i][j] == signed(i + j)); 49 | } 50 | 51 | void test_A() 52 | { 53 | { 54 | A_array<3> arr(3, 2, 1, 0.5); 55 | assert(count_A == 6); 56 | assert(arr[2][1][0].d == 0.5); 57 | } 58 | assert(count_A == 0); 59 | { 60 | // Move copy. 61 | auto f = [](){return A_array<2>(2, 1);}; 62 | auto arr2 = f(); 63 | assert(count_A == 2); 64 | assert(arr2.size() == 2); 65 | assert(arr2.dimension() == 2); 66 | 67 | decltype(arr2) arr3(0, 0); 68 | arr3 = std::move(arr2); 69 | assert(count_A == 2); 70 | } 71 | assert(count_A == 0); 72 | } 73 | 74 | int main() 75 | { 76 | test_int(); 77 | test_A(); 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /test/test_rational.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "kedixa/rational.h" 9 | 10 | using namespace std; 11 | using rational = kedixa::rational; 12 | using ubigint = kedixa::unsigned_bigint; 13 | 14 | const std::string sma = "111222333444555666777888999000"; 15 | ubigint uone(1), uthree(3), uten(10), uma(sma); 16 | rational zero, one_third(uone, uthree), neg_one_third(uone, uthree, true); 17 | rational one(uone), one_1(uone, uone), one_2(uthree, uthree), one_3(uma, uma); 18 | rational one_ma(uone, uma), neg_one_ma(uone, uma, true); 19 | rational ten_ma(uten, uma), neg_ten_ma(uten, uma, true); 20 | 21 | void check(); 22 | 23 | int main() 24 | { 25 | check(); 26 | return 0; 27 | } 28 | 29 | void check_to_string() 30 | { 31 | assert(zero.to_string() == "0"); 32 | assert(one_third.to_string() == "1/3"); 33 | assert(neg_one_third.to_string() == "-1/3"); 34 | assert(one_3.to_string() == "1"); 35 | assert(neg_one_ma.to_string() == "-1/" + sma); 36 | assert(neg_ten_ma.to_string() == "-1/" + sma.substr(0, sma.length() - 1)); 37 | } 38 | 39 | void check_relation() 40 | { 41 | assert(zero == zero); 42 | assert(zero < one); 43 | assert(zero >= neg_one_third); 44 | assert(neg_one_third < one); 45 | assert(one_1 == one_2 && one_2 == one_3); 46 | assert(ten_ma <= one); 47 | assert(ten_ma != neg_ten_ma); 48 | } 49 | 50 | void check_add_sub() 51 | { 52 | assert(zero + zero == zero); 53 | assert(one_third + neg_one_third == zero); 54 | assert(ten_ma + neg_ten_ma == zero); 55 | assert(one + one_third == rational(ubigint(4), ubigint(3))); 56 | assert(one + one_third + one_1 + one_1 + neg_one_third == rational(uthree)); 57 | assert(one_third - neg_one_third + one_third == one); 58 | assert(one + neg_one_third == one_third + one_third); 59 | } 60 | 61 | void check_multi_div() 62 | { 63 | assert(zero * ten_ma == zero); 64 | assert(one * one_1 == one_2); 65 | assert(neg_ten_ma * one == -one * ten_ma); 66 | assert(one / neg_one_third == -(one / one_third)); 67 | assert(ten_ma / neg_ten_ma == -one); 68 | assert(zero / ten_ma == zero); 69 | } 70 | 71 | void check_hash() 72 | { 73 | unordered_set st; 74 | st.insert(zero); 75 | st.insert(one_third); 76 | st.insert(neg_ten_ma); 77 | st.insert(neg_one_ma); 78 | assert(st.find(neg_ten_ma) != st.end()); 79 | assert(st.find(ten_ma) == st.end()); 80 | } 81 | 82 | void check_convert() 83 | { 84 | assert(!zero); 85 | assert(one); 86 | assert(neg_ten_ma); 87 | long double d = neg_ten_ma.to_ld(); 88 | static_cast(d); 89 | assert(one_third.to_ld() == 1.0L/3.0); 90 | } 91 | 92 | void check_others() 93 | { 94 | assert(one_third.get_num() == uone); 95 | assert(neg_one_third.get_den() == uthree); 96 | assert(neg_ten_ma.get_sign() == true); 97 | assert(neg_one_third.num_size() == 1); 98 | assert(neg_one_third.to_decimal(3) == "-0.333"); 99 | auto x = one_third; 100 | x.reciprocal(); 101 | assert(x * one_third == one); 102 | 103 | // pi/2 = 1 + 1/3 + 1/3 * 2/5 + 1/3 * 2/5 * 3/7 + ... 104 | rational pi(ubigint(1)); 105 | rational rat(ubigint(1)); 106 | for(size_t i = 1; i < 350; ++i) 107 | { 108 | rat *= rational(ubigint(i), ubigint(2*i+1)); 109 | pi += rat; 110 | } 111 | pi *= rational(ubigint(2)); 112 | const string pi100 = "3.141592653589793238462643383279" 113 | "5028841971693993751058209749445923" 114 | "078164062862089986280348253421170679"; 115 | assert(pi.to_decimal(100) == pi100); 116 | } 117 | 118 | void check() 119 | { 120 | check_to_string(); 121 | check_relation(); 122 | check_add_sub(); 123 | check_multi_div(); 124 | check_hash(); 125 | check_convert(); 126 | check_others(); 127 | } 128 | -------------------------------------------------------------------------------- /test/test_timer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "kedixa/timer.h" 3 | 4 | constexpr int N = 10000000; 5 | 6 | void test01() { 7 | long long sum = 0; 8 | 9 | kedixa::timer t; 10 | for(int i = 0; i < N/2; ++i) 11 | sum += i; 12 | t.pause(); 13 | 14 | // do some other things 15 | 16 | t.start(); 17 | for(int i = N/2; i < N; ++i) 18 | sum += i; 19 | 20 | std::cout << "Sum = " << sum << std::endl; 21 | std::cout << "It takes " << t.stop() << " seconds," << std::endl; 22 | std::cout << "which is " << t.as_nsec() << " nanoseconds." << std::endl; 23 | } 24 | 25 | void test02() { 26 | long long sum = 0; 27 | 28 | int64_t nano = kedixa::timer::timeit([&sum](int n){ 29 | for(int i = 0; i < n; i++) 30 | sum += i; 31 | }, N); 32 | 33 | std::cout << "Sum = " << sum << std::endl; 34 | std::cout << "It takes " << nano << " nanoseconds." << std::endl; 35 | } 36 | 37 | int main() { 38 | 39 | test01(); 40 | test02(); 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /test/test_unsigned_bigint.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "kedixa/unsigned_bigint.h" 9 | using namespace std; 10 | using ubig = kedixa::unsigned_bigint; 11 | 12 | ubig zero, one(1), two(2), ten(10), hundred(100); 13 | ubig b1(123456789), b2(987654321), b3(4294967295); 14 | random_device rd; 15 | 16 | void check(); 17 | 18 | ubig fast_pow(const ubig &b, int p) 19 | { 20 | ubig x(1), y(b); 21 | while(p>0) 22 | { 23 | if(p&1) x*=y; 24 | y *= y; 25 | p>>=1; 26 | } 27 | return x; 28 | } 29 | int main() 30 | { 31 | check(); 32 | return 0; 33 | } 34 | 35 | void check_to_string() 36 | { 37 | assert(zero.to_string() == "0"); 38 | assert(one.to_string() == "1"); 39 | assert(two.to_string() == "2"); 40 | assert(ten.to_string() == "10"); 41 | assert(hundred.to_string() == "100"); 42 | for(size_t i = 0; i < 100; ++i) 43 | { 44 | unsigned tmp = rd(); 45 | assert(ubig(tmp).to_string() == to_string(tmp)); 46 | } 47 | assert(b1.to_string() == "123456789"); 48 | assert(b3.to_string() == "4294967295"); 49 | assert(ubig(vector({0x1AD98412, 0x329087EB})).to_string() == "3643561542380258322"); 50 | assert(ubig(string(100, '8')).to_string() == string(100, '8')); 51 | } 52 | 53 | void check_relation() 54 | { 55 | assert(zero == zero); 56 | assert(zero < one); 57 | assert(123 > hundred); 58 | assert(hundred == hundred); 59 | assert(b3 >= b2); 60 | assert(b1 <= b3); 61 | assert(b1 != 666); 62 | assert(hundred.compare(ten) > 0); 63 | assert(hundred.compare(hundred) == 0); 64 | assert(ubig("555555555555") > 0); 65 | } 66 | 67 | void check_add_sub() 68 | { 69 | assert((zero + zero).to_string() == "0"); 70 | assert((zero + one).to_string() == "1"); 71 | assert((one + one).to_string() == "2"); 72 | assert((one + ten).to_string() == "11"); 73 | assert((ten + hundred).to_string() == "110"); 74 | assert((b1 + b2).to_string() == "1111111110"); 75 | assert((b1 + b3).to_string() == "4418424084"); 76 | ubig ub1("1234567890987654321"), ub2("9876543210123456789"), ub3("11111111101111111110"); 77 | assert(ub1 + ub2 == ub3); 78 | assert(ub3 - ub1 == ub2); 79 | assert(ub3 - ub2 == ub1); 80 | assert(ub3 - hundred == ub3 - 100); 81 | assert(hundred - ten == 90); 82 | ubig ub4(12345); 83 | assert(++ub4 == 12346); 84 | assert(ub4-- == 12346); 85 | assert(ub4++ == 12345); 86 | assert(--ub4 == 12345); 87 | bool e = false; 88 | try { ubig ub5 = ten - hundred; } 89 | catch(exception &ex) { e = true; } 90 | assert(e); 91 | } 92 | 93 | void check_multi_div() 94 | { 95 | ubig ub1 = b1 * b2 * b3; 96 | assert(ub1.to_string() == "523696662822067941618527355"); 97 | assert(ub1 / b1 == b2 * b3); 98 | assert(ub1 / b2 == b1 * b3); 99 | assert(ub1 / b3 == b1 * b2); 100 | assert(ub1 * ub1 / ub1 == ub1); 101 | assert(ub1 * b1 == b1 * b1 * b2 * b3); 102 | assert(ub1 / ub1 == 1); 103 | bool e = false; 104 | try { ubig ub2 = ub1 / zero; } 105 | catch(exception &ex) { e = true; } 106 | assert(e); 107 | ubig ub3 = one; 108 | for(size_t i = 0; i < 100; ++i) 109 | ub3 *= 1234567; 110 | assert(ub3 == fast_pow(ubig(1234567), 100)); 111 | ubig ub4(string(12345, '4')), ub5(string(1234, '5')); 112 | assert(ub5 * ub4 / ub5 == ub4); 113 | } 114 | 115 | void check_hash() 116 | { 117 | unordered_set st; 118 | st.insert(zero); 119 | st.insert(one); 120 | st.insert(two); 121 | st.insert(ten); 122 | st.insert(hundred); 123 | assert(st.find(zero) != st.end()); 124 | } 125 | 126 | void check_convert() 127 | { 128 | assert(hundred.to_uint() == 100); 129 | unsigned long long ull = 31415926535897ULL; 130 | ubig ub1(std::to_string(ull)); 131 | assert(ub1.to_ull() == ull); 132 | 133 | bool e = false; 134 | try { ub1.to_uint(); } 135 | catch(exception &ex) { e = true; } 136 | assert(e); 137 | 138 | long double d = ub1.to_ld(); 139 | static_cast(d); 140 | 141 | e = false; 142 | int ldsz = std::numeric_limits::max_exponent + 2; 143 | ubig ub2 = ubig(1u) << ldsz; 144 | try { ub2.to_ld(); } 145 | catch(exception &ex) { e = true; } 146 | assert(e); 147 | 148 | assert(abs(ub1.to_ld()-ull) < 1e-7); 149 | } 150 | 151 | void check_others() 152 | { 153 | assert((one ^ hundred) == (1 ^ 100)); 154 | assert((ten | hundred) == (10 | 100)); 155 | assert((two & ten) == (2 & 10)); 156 | assert((b3 << 5).to_string() == to_string(4294967295LL << 5)); 157 | assert(b3 >> 5 == 4294967295U >> 5); 158 | } 159 | 160 | void check() 161 | { 162 | check_to_string(); 163 | check_relation(); 164 | check_add_sub(); 165 | check_multi_div(); 166 | check_hash(); 167 | check_convert(); 168 | check_others(); 169 | } 170 | 171 | --------------------------------------------------------------------------------