aboutsummaryrefslogtreecommitdiff
path: root/bigint.h
blob: 0378493b41035e35dcfe1cf60f38780d59a49cca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <utility>
#include <cstdint>

//A bigint implementation based on unsigned 32-bit digits.
//The implementation relies on having native 64-bit arithmetic (or specifically,
//(2*digit_bits)-bit arithmetic).
class Bigint{
public:
	typedef uint32_t digit_t;
	typedef int32_t sdigit_t; //signed version
	typedef uint64_t longdigit_t; //should be twice as large as digit_t
	typedef int64_t slongdigit_t; //signed version
	static const int digit_bits=8*sizeof(digit_t);

private:
	std::vector<digit_t> digits; //little-endian order
	int sign; //-1 for negative, 1 for positive; -0 is not a valid state

	static void add(Bigint&,const Bigint&); //ignores sign of arguments
	static void subtract(Bigint&,const Bigint&); //ignores sign of arguments
	static Bigint product(const Bigint&,const Bigint&);

	void shrink(); //prune unnecessary zero digits on top
	void normalise(); //make sure -0 doesn't occur

	//This function is called from all relevant return points of the member functions. It's
	//basically a debug check, but it can't hurt to have it since it takes few cpu cycles.
	void checkconsistent();

	static std::pair<Bigint,Bigint> divmod(Bigint a,const Bigint &div,int maxdepth); //ignores all signs

public:
	Bigint();
	Bigint(const Bigint&)=default;
	Bigint(Bigint&&);

	explicit Bigint(const std::string&); //Initialise with a large value
	explicit Bigint(sdigit_t); //Initialise with a small value
	explicit Bigint(digit_t);
	explicit Bigint(slongdigit_t);
	explicit Bigint(longdigit_t);

	Bigint& operator=(const Bigint&)=default;
	Bigint& operator=(Bigint&&);
	Bigint& operator=(slongdigit_t);
	Bigint& operator=(longdigit_t);
	Bigint& operator=(sdigit_t);
	Bigint& operator=(digit_t);

	Bigint& operator+=(const Bigint&);
	Bigint& operator-=(const Bigint&);
	Bigint& operator*=(const Bigint&);
	Bigint& operator+=(slongdigit_t);
	Bigint& operator-=(slongdigit_t);
	Bigint& operator*=(slongdigit_t);
	Bigint& operator<<=(int);
	Bigint& operator>>=(int);
	Bigint& negate();
	//Division and modulo operators are explicitly NOT included, to promote clever usage
	//of the divmod function, which combines both.

	Bigint operator+(const Bigint&) const;
	Bigint operator-(const Bigint&) const;
	Bigint operator*(const Bigint&) const;
	Bigint operator+(slongdigit_t) const;
	Bigint operator-(slongdigit_t) const;
	Bigint operator*(slongdigit_t) const;
	Bigint operator<<(int) const;
	Bigint operator>>(int) const;

	//Uses *mathematical* division-with-remainder.
	//If we look at {q,r} = x.divmod(y), then x = q*y + r, and 0<=r<|q|. This is *not* compatible with many other
	//programming languages (and, for that matter, the C++ built-in behaviour).
	std::pair<Bigint,Bigint> divmod(const Bigint&) const;

	bool operator==(const Bigint&) const;
	bool operator!=(const Bigint&) const;
	bool operator<(const Bigint&) const;
	bool operator>(const Bigint&) const;
	bool operator<=(const Bigint&) const;
	bool operator>=(const Bigint&) const;
	bool operator==(slongdigit_t) const;
	bool operator!=(slongdigit_t) const;
	bool operator<(slongdigit_t) const;
	bool operator>(slongdigit_t) const;
	bool operator<=(slongdigit_t) const;
	bool operator>=(slongdigit_t) const;

	int compare(const Bigint&) const; //-1: <; 0: ==; 1: >
	int compare(slongdigit_t) const;
	int compareAbs(const Bigint&) const; //-1: <; 0: ==; 1: >; disregards sign
	int compareAbs(slongdigit_t) const;

	int bitcount() const;
	slongdigit_t lowdigits() const;
	bool even() const;
	bool odd() const;
	int trailingZeros() const; //throws domain_error if called on zero value

	std::string serialiseMantissa() const; //stores everything but the sign
	void deserialiseMantissa(const std::string&); //restores non-negative number; can throw invalid_argument
	std::vector<bool> bits() const; //Stores bits in little-endian order

	friend std::istream& operator>>(std::istream&,Bigint&);
	friend std::ostream& operator<<(std::ostream&,Bigint);


	static Bigint mone; //Some small values to save a constructor call
	static Bigint zero;
	static Bigint one;
	static Bigint two;
};

std::istream& operator>>(std::istream&,Bigint&);
std::ostream& operator<<(std::ostream&,Bigint); //The output operator supports the `hex` modifier