As sort of a follow up to my previous question from a year ago, what are some suggestions you can think of that will improve this code, whether is directly programming related or algorithm related? I know there are better algorithms for multiplication and division, but I don't understand many of them (yet).
I have improved my code a lot since last year, but its still very slow.
Sorry for the long code, but there is a lot of stuff, even after removing over 100000 characters. Also, all this modifying might have messed up some of the formatting.
Please visit http://calccrypto.wikidot.com/programming:integer for the most up to date code. The code below is only for reference and may not have the bug fixes suggested put in
// Note: All of the operators have been templated or explicitly overloaded for standard
// integer types in the full code
// go to http://calccrypto.wikidot.com/programming:integer
// for an older version of this class because most functions haven't
// been touched for a long time
// i removed them because they took up so much space, and apparantly there
// is a limit of 300000 characters to post
#include <cstdlib>
#include <deque>
#include <iostream>
#ifndef __INTEGER__
#define __INTEGER__
class integer{
private:
bool SIGN; // false = positive, true = negative
std::deque <uint8_t> value; // holds the actual value in base256
void clean(){ // remove 0 bytes from top of deque to save memory
while (value.size() && !value[0])
value.pop_front();
}
public:
// Constructors
integer(){SIGN = false;}
// similar for uint8_t, uint16_t, and uint64_t
integer(uint32_t rhs){
SIGN = false;
while (rhs){
value.push_front(rhs & 255);
rhs >>= 8;
}
}
// similar for int8_t, int16_t, and int64_t
integer(int32_t rhs){
SIGN = (rhs < 0);
if (rhs < 0)
rhs = -rhs;
while (rhs){
value.push_front(rhs & 255);
rhs >>= 8;
}
}
integer(const integer & rhs){
value = rhs.value;
SIGN = rhs.SIGN;
clean();
}
integer(std::deque <uint8_t> & val){
value = val;
SIGN = false;
clean();
}
integer(bool s, std::deque <uint8_t> & val){
value = val;
SIGN = value.size()?s:false;
clean();
}
integer(std::string str, int base){
integer temp = 0;
SIGN = false;
if (str[0] == '-'){
SIGN = true;
str = str.substr(1, str.size() - 1);
}
switch (base){
case 2:
for(unsigned int x = 0; x < str.size(); x++)
temp = (temp << 1) + (str[x] - 48);
break;
case 8:
for(unsigned int x = 0; x < str.size(); x++)
temp = (temp << 3) + (str[x] - 48);
break;
case 10:
for(unsigned int x = 0; x < str.size(); x++)
temp = (temp << 3) + (temp << 1) + (str[x] - 48);
break;
case 16:
for(unsigned int x = 0; x < str.size(); x++){
temp <<= 4;
if ((0x2f < str[x]) && (str[x] < 0x3a)) // 0 - 9
temp += str[x] - 0x30;
else if ((0x60 < str[x]) && (str[x] < 0x67)) // a - f
temp += str[x] - 0x57;
else if ((0x40 < str[x]) && (str[x] < 0x47)) // A - F
temp += str[x] - 0x37;
else{
std::cerr << "Error: Character not between 'a' and 'f' found." << std::endl;
exit(1);
}
}
break;
case 256:
for(unsigned int x = 0; x < str.size(); x++)
temp.value.push_back(str[x]);
break;
default:
break;
}
value = temp.value;
}
// RHS input args only
// Assignment Operator
// similar for uint8_t, uint16_t, and uint64_t
integer & operator=(uint32_t rhs){
value.clear();
SIGN = false;
while (rhs){
value.push_front(rhs & 255);
rhs >>= 8;
}
return *this;
}
// similar for int8_t, int16_t, and int64_t
integer & operator=(int32_t rhs){
value.clear();
SIGN = (rhs < 0);
if (rhs < 0)
rhs = -rhs;
while (rhs){
value.push_front(rhs & 255);
rhs >>= 8;
}
return *this;
}
integer & operator=(integer rhs){
value = rhs.value;
SIGN = rhs.SIGN;
return *this;
}
// Typecast Operators
operator bool(){
return (bool) value.size();
}
operator char(){
if (!value.size())
return 0;
return (char) value.back();
}
operator uint8_t(){
if (!value.size())
return 0;
return value.back();
}
// similar for uint16_t, and uint64_t
operator uint32_t(){
uint32_t out = 0;
for(uint8_t x = 0; x < ((4 < value.size())?4:value.size()); x++)
out = (out << 8) + (uint8_t) value[value.size() - x - 1];
return out;
}
operator int8_t(){
if (!value.size())
return 0;
int8_t out = value.back();
if (SIGN)
out = -out;
return out;
}
// similar for int16_t, and int64_t
operator int32_t(){
int64_t out = 0;
for(uint8_t x = 0; x < ((4 < value.size())?4:value.size()); x++)
out = (out << 8) + (uint8_t) value[value.size() - x - 1];
if (SIGN)
out = -out;
return out;
}
// Bitwise Operators
integer operator&(integer rhs){
std::deque <uint8_t> out;
for(std::deque <uint8_t>::reverse_iterator i = value.rbegin(), j = rhs.value.rbegin(); (i != value.rend()) && (j != rhs.value.rend()); i++, j++)
out.push_front(*i & *j);
return integer(SIGN & rhs.SIGN, out);
}
integer operator|(integer rhs){
std::deque <uint8_t> out;
std::deque <uint8_t>::reverse_iterator i = value.rbegin(), j = rhs.value.rbegin();
for(; (i != value.rend()) && (j != rhs.value.rend()); i++, j++)
out.push_front(*i | *j);
while (i != value.rend())
out.push_front(*i++);
while (j != rhs.value.rend())
out.push_front(*j++);
return integer(SIGN | rhs.SIGN, out);
}
integer operator^(integer rhs){
std::deque <uint8_t> out;
std::deque <uint8_t>::reverse_iterator i = value.rbegin(), j = rhs.value.rbegin();
for(; (i != value.rend()) && (j != rhs.value.rend()); i++, j++)
out.push_front(*i ^ *j);
while (i != value.rend())
out.push_front(*i++);
while (j != rhs.value.rend())
out.push_front(*j++);
return integer(SIGN ^ rhs.SIGN, out);
}
integer operator&=(integer rhs){
*this = *this & rhs;
return *this;
}
integer operator|=(integer rhs){
*this = *this | rhs;
return *this;
}
integer operator^=(const integer rhs){
*this = *this ^ rhs;
return *this;
}
integer operator~(){
std::deque <uint8_t> out = value;
for(unsigned int i = 1; i < out.size(); i++)
out[i] ^= 0xff;
uint8_t mask = 128;
while (!(out[0] & mask))
mask >>= 1;
while (mask){
out[0] ^= mask;
mask >>= 1;
}
return integer(SIGN, out);
}
// Bit Shift Operators
// left bit shift. sign is maintained
integer operator<<(uint64_t shift){
if (!*this || !shift)
return *this;
std::deque <uint8_t> out = value;
for(uint64_t i = 0; i < (shift >> 3); i++)
out.push_back(0);
shift &= 7;
if (shift){
out.push_back(0);
return integer(SIGN, out) >> (8 - shift);
}
return integer(SIGN, out);
}
integer operator<<(integer shift){
integer out = *this;
for(integer i = 0; i < (shift >> 3); i++)
out.value.push_back(0);
return out << (uint64_t) (shift & 7);
}
// right bit shift. sign is maintained
integer operator>>(uint64_t shift){
if (shift >= bits())
return integer(0);
std::deque <uint8_t> out = value;
for(uint64_t i = 0; i < (shift >> 3); i++)
out.pop_back();
shift &= 7;
if (shift){
std::deque <uint8_t> v;
for(unsigned int i = out.size() - 1; i != 0; i--)
v.push_front(((out[i] >> shift) | (out[i - 1] << (8 - shift))) & 0xff);
v.push_front(out[0] >> shift);
out = v;
}
return integer(SIGN, out);
}
integer operator>>(integer shift){
integer out = *this;
for(integer i = 0; i < (shift >> 3); i++)
out.value.pop_back();
return out >> (uint64_t) (shift & 7);
}
// Logical Operators
bool operator!(){
return !(bool) *this;
}
bool operator&&(integer rhs){
return (bool) *this && (bool) rhs;
}
bool operator||(integer rhs){
return ((bool) *this) || (bool) rhs;
}
// Comparison Operators
bool operator==(integer rhs){
return ((SIGN == rhs.SIGN) && (value == rhs.value));
}
bool operator!=(integer rhs){
return !(*this == rhs);
}
private:
// operator> not considering signs
bool gt(integer & lhs, integer & rhs){
if (lhs.value.size() > rhs.value.size())
return true;
if (lhs.value.size() < rhs.value.size())
return false;
if (lhs.value == rhs.value)
return false;
for(unsigned int i = 0; i < lhs.value.size(); i++)
if (lhs.value[i] != rhs.value[i])
return lhs.value[i] > rhs.value[i];
return false;
}
public:
bool operator>(integer rhs){
if (SIGN & !rhs.SIGN) // - > +
return false;
else if (!SIGN & rhs.SIGN) // + > -
return true;
else if (SIGN & rhs.SIGN) // - > -
return !gt(*this, rhs);
// else (!SIGN & !rhs.SIGN) // + > +
return gt(*this, rhs);
}
bool operator>=(integer rhs){
return ((*this > rhs) | (*this == rhs));
}
private:
// operator< not considering signs
bool lt(integer & lhs, integer & rhs){
if (lhs.value.size() < rhs.value.size())
return true;
if (lhs.value.size() > rhs.value.size())
return false;
if (lhs.value == rhs.value)
return false;
for(unsigned int i = 0; i < lhs.value.size(); i++)
if (lhs.value[i] != rhs.value[i])
return lhs.value[i] < rhs.value[i];
return false;
}
public:
bool operator<(integer rhs){
if (SIGN & !rhs.SIGN) // - < +
return true;
else if (!SIGN & rhs.SIGN) // + < -
return false;
else if (SIGN & rhs.SIGN) // - < -
return !lt(*this, rhs);
// else (!SIGN & !rhs.SIGN) // + < +
return lt(*this, rhs);
}
bool operator<=(integer rhs){
return ((*this < rhs) | (*this == rhs));
}
private:
// Arithmetic Operators
integer add(integer & lhs, integer & rhs){
std::deque <uint8_t> out;
std::deque <uint8_t>::reverse_iterator i = lhs.value.rbegin(), j = rhs.value.rbegin();
bool carry = false;
uint16_t sum;
for(; ((i != lhs.value.rend()) && (j != rhs.value.rend())); i++, j++){
sum = *i + *j + carry;
out.push_front(sum);
carry = (sum > 255);
}
for(; i != lhs.value.rend(); i++){
sum = *i + carry;
out.push_front(sum);
carry = (sum > 255);
}
for(; j != rhs.value.rend(); j++){
sum = *j + carry;
out.push_front(sum);
carry = (sum > 255);
}
if (carry)
out.push_front(1);
return integer(false, out);
}
public:
integer operator+(integer rhs){
if (!rhs)
return *this;
if (!*this)
return rhs;
integer out = *this;
if (SIGN == rhs.SIGN){
out = add(out, rhs);
out.SIGN = SIGN;
}
else if (gt(out, rhs)){
if ((!SIGN & rhs.SIGN) | (SIGN & !rhs.SIGN)) // + + - - + +
out = sub(out, rhs);
if ((!SIGN & !rhs.SIGN) | (SIGN & rhs.SIGN)) // + + + - + -
out = add(out, rhs);
out.SIGN = SIGN;
}
else if (lt(out, rhs)){
if ((!SIGN & rhs.SIGN) | (SIGN & !rhs.SIGN)){ // + + - - + +
out = sub(rhs, out);
out.SIGN = !SIGN;
}
if ((SIGN & rhs.SIGN) | (!SIGN & !rhs.SIGN)){ // + + + - + -
out = add(rhs, out);
out = SIGN;
}
}
else{ //if (eq(out, rhs)){
if ((SIGN & rhs.SIGN) | (!SIGN & !rhs.SIGN))
return integer(0);
//if ((SIGN & !rhs.SIGN) | (!SIGN & rhs.SIGN))
out = out << 1;
out.SIGN = SIGN;
}
if (!out.value.size()) // if the value became 0
out.SIGN = false;
return out;
}
integer operator+=(integer rhs){
*this = *this + rhs;
return *this;
}
private:
// Subtraction as done by hand
integer long_sub(integer & lhs, integer & rhs){
// rhs always smaller than lhs
unsigned int lsize = lhs.value.size() - 1;
unsigned int rsize = rhs.value.size() - 1;
for(unsigned int x = 0; x < rsize + 1; x++){
// if rhs digit is smaller than lhs digit, subtract
if (rhs.value[rsize - x] <= lhs.value[lsize - x])
lhs.value[lsize - x] -= rhs.value[rsize - x];
else{// carry
unsigned int y = lsize - x - 1;
while (!lhs.value[y])
y--;
lhs.value[y]--;
y++;
for(; y < lsize - x; y++)
lhs.value[y] = 0xff;
lhs.value[y] = ((uint16_t) lhs.value[y]) + 256 - rhs.value[rsize - x];
}
}
return lhs;
}
// implemented but erased here and commented out in code
// // Two's Complement Subtraction
integer sub(integer & lhs, integer & rhs){
if (!rhs)
return lhs;
if (!lhs)
return -rhs;
if (lhs == rhs)
return 0;
return long_sub(lhs, rhs);
// return two_comp_sub(lhs, rhs);
}
public:
integer operator-(integer rhs){
integer out = *this;
if (gt(out, rhs)){
if ((!SIGN & rhs.SIGN) | (SIGN & !rhs.SIGN)) // + - - - - +
out = add(out, rhs);
if ((!SIGN & !rhs.SIGN) | (SIGN & rhs.SIGN)) // + - + - - -
out = sub(out, rhs);
out.SIGN = SIGN;
}
else if (lt(out, rhs)){
if ((!SIGN & rhs.SIGN) | (SIGN & !rhs.SIGN)){ // + - - - - +
out = add(out, rhs);
out.SIGN = SIGN;
}
if ((SIGN & rhs.SIGN) | (!SIGN & !rhs.SIGN)){ // + - + - - -
out = sub(rhs, out);
out.SIGN = !SIGN;
}
}
else{ //if (eq(out, rhs)){
if ((SIGN & rhs.SIGN) | (!SIGN & !rhs.SIGN))
return integer(0);
//if ((SIGN & !rhs.SIGN) | (!SIGN & rhs.SIGN))
out <<= 1;
out.SIGN = SIGN;
}
if (!out.value.size()) // if the value became 0
out.SIGN = false;
clean();
return out;
}
integer operator-=(integer rhs){
*this = *this - rhs;
return *this;
}
private:
// implemented but erased here and commented out in code:
// // Peasant Multiplication
// // Recurseive Peasant Algorithm
// // Recursive Multiplication
// // Karatsuba Algorithm O(n^log2(3) = n ^ 1.585)
// Long multiplication
integer long_mult(integer lhs, integer rhs){
unsigned int zeros = 0;
integer row, out = 0;
for(std::deque <uint8_t>::reverse_iterator i = lhs.value.rbegin(); i != lhs.value.rend(); i++){
row.value = std::deque <uint8_t>(zeros++, 0); // zeros on the right hand side
uint8_t carry = 0;
for(std::deque <uint8_t>::reverse_iterator j = rhs.value.rbegin(); j != rhs.value.rend(); j++){
uint16_t prod = (uint16_t(*i) * uint16_t(*j)) + carry;// multiply through
row.value.push_front(prod & 0xff);
carry = prod >> 8;
}
if (carry)
row.value.push_front(carry);
out = add(out, row);
}
return out;
}
public:
integer operator*(integer rhs){
if ((!*this) || (!rhs)) // if multiplying by 0
return 0;
if (*this == 1) // if multiplying by 1
return rhs;
if (rhs == 1) // if multiplying by 1
return *this;
bool s = SIGN ^ rhs.SIGN;
integer out = *this;
out.SIGN = false;
rhs.SIGN = false;
if (rhs.abs() == 10){ // if rhs == 10
out = (out << 3) + (out << 1);
out.SIGN = s;
return out;
}
if (out.abs() == 10){ // if lhs == 10
out = (rhs << 3) + (rhs << 1);
out.SIGN = s;
return out;
}
// while lhs is multiple of 2
while (!(rhs & 1)){
rhs >>= 1;
out <<= 1;
}
// out = peasant(out, rhs);
// out = recursive_peasant(out, rhs);
// out = recursive_mult(out, rhs);
// out = karatsuba(out, rhs);
out = long_mult(out, rhs);
out.SIGN = s;
if (!out.value.size()) // if the value became 0
out.SIGN = false;
return out;
}
integer operator*=(integer rhs){
*this = *this * rhs;
return *this;
}
private:
// implemented but erased here and commented out in code:
// // Long Division returning both quotient and remainder
// // Recursive Division that returns both the quotient and remainder
// Non-Recursive version of above algorithm
std::deque <integer> divmod(integer & lhs, integer & rhs){
std::deque <integer> qr;
qr.push_back(0);
qr.push_back(0);
for(unsigned int x = lhs.bits(); x > 0; x--){
qr[0] <<= 1;
qr[1] <<= 1;
if (lhs[x - 1])
qr[1]++;
if (qr[1] >= rhs){
qr[1] -=rhs;
qr[0]++;
}
}
return qr;
}
// division ignoring signs
std::deque <integer> dm(integer & lhs, integer & rhs){
if (!rhs){ // divide by 0 error
std::cerr << "Error: division or modulus by zero" << std::endl;
exit(1);
}
std::deque <integer> out;
if (rhs == 1){ // divide by 1 check
out.push_back(lhs);
out.push_back(0);
return out;
}
if (lhs == rhs){ // divide by same value check
out.push_back(1);
out.push_back(0);
return out;
}
if (!lhs){ // 0 / rhs check
out.push_back(0);
out.push_back(0);
return out;
}
if (lt(lhs, rhs)){ // lhs < rhs check
out.push_back(0);
out.push_back(lhs);
return out;
}
// Check for powers of two /////////////////////
// Cannot do it the easy way for some reason
if (!(rhs & 1)){
uint64_t s = 0;
integer copyd(rhs);
while (!(copyd & 1)){
copyd >>= 1;
s++;
}
if (copyd == 1){
out.push_back(lhs >> s);
out.push_back(lhs - (out[0] << s));
return out;
}
}
////////////////////////////////////////////////
// return long_div(lhs, rhs);
// return recursive_divmod(lhs, rhs);
return divmod(lhs, rhs);
}
public:
integer operator/(integer rhs){
bool s = SIGN ^ rhs.SIGN;
integer lhs = *this;
lhs.SIGN = false;
rhs.SIGN = false;
integer out = dm(lhs, rhs)[0];
out.SIGN = s;
if (!out.value.size()) // if the value became 0
out.SIGN = false;
return out;
}
integer operator/=(integer rhs){
*this = *this / rhs;
return *this;
}
integer operator%(integer rhs){
bool s1 = SIGN;
bool s2 = rhs.SIGN;
integer lhs = *this;
lhs.SIGN = false;
rhs.SIGN = false;
integer out = dm(lhs, rhs)[1];
if (out.value.size())
if (s1 == s2)
out.SIGN = s1;
else{
out = rhs - out;
out.SIGN = s2;
}
else //if (!out.value.size()) // if the value became 0
out.SIGN = false;
return out;
}
integer operator%=(integer rhs){
*this = *this % rhs;
return *this;
}
// Increment Operator
integer & operator++(){
*this += 1;
return *this;
}
integer operator++(int){
integer temp(*this);
++*this;
return temp;
}
// Decrement Operator
integer & operator--(){
*this -= 1;
return *this;
}
integer operator--(int){
integer temp(*this);
--*this;
return temp;
}
// Nothing done since promotion doesnt work here
integer operator+(){
return *this;
}
// Flip Sign
integer operator-(){
integer out = *this;
if (out.value.size())
out.SIGN ^= true;
return out;
}
// get private values
bool sign(){
return SIGN; // false = pos, true = neg
}
unsigned int bits(){
if (!value.size())
return 0;
unsigned int out = value.size() << 3;
uint8_t mask = 128;
while (!(value[0] & mask)){
out--;
mask >>= 1;
}
return out;
}
unsigned int bytes(){
return value.size();
}
std::deque <uint8_t> data(){
return value;
}
// Miscellaneous Functions
integer twos_complement(unsigned int b = 0){
std::deque <uint8_t> out = value;
for(unsigned int i = 1; i < out.size(); i++)
out[i] ^= 0xff;
uint8_t mask = 128;
while (!(out[0] & mask))
mask >>= 1;
integer top = integer(1) << ((uint64_t) (out.size() - 1) << 3);
while (mask){
out[0] ^= mask;
mask >>= 1;
top <<= 1;
}
integer OUT(SIGN, out);
while (b){
OUT ^= top;
top <<= 1;
b--;
}
return OUT + 1;
}
integer abs(){
integer out = *this;
out.SIGN = false;
return out;
}
void fill(uint64_t b){
// fills an integer with 1s
value = std::deque <uint8_t>(b >> 3, 255);
if (b & 7)
value.push_front((1 << (b & 7)) - 1);
}
bool operator[](unsigned int b){
// get bit, where 0 is the lsb and bits() - 1 is the msb
if (b >= bits()) // if given index is larger than bits in this value, return 0
return 0;
return (value[value.size() - (b >> 3) - 1] >> (b & 7)) & 1;
}
// Output value as a string in bases 2 to 16, and 256
std::string str(integer base = 10, unsigned int length = 0){
std::string out = "";
if (base == 256){
if (!value.size())
out = std::string(1, 0);
for(unsigned int x = 0; x < value.size(); x++)
out += std::string(1, value[x]);
while (out.size() < length)
out = std::string(1, 0) + out;
if (SIGN){
if (!out[0])
out = out.substr(1, out.size() - 1);
out = "-" + out;
}
}
else{
if ((base < 2) || (base > 16)) // if base outside of 2 <= base <= 16
base = 10; // set to default value of 10
integer rhs = *this;
static const std::string B16 = "0123456789abcdef";
std::deque <integer> qr;
do{
qr = dm(rhs, base);
out = B16[qr[1]] + out;
rhs = qr[0];
} while (rhs);
while (out.size() < length)
out = "0" + out;
if (SIGN){
if (out[0] == '0')
out = out.substr(1, out.size() - 1);
out = "-" + out;
}
}
return out;
}
};
// lhs type T as first arguemnt
// erased because they were taking up too much space
// IO Operators
std::ostream & operator<<(std::ostream & stream, integer rhs){
if (stream.flags() & stream.oct)
stream << rhs.str(8);
else if (stream.flags() & stream.hex)
stream << rhs.str(16);
else
stream << rhs.str(10);
return stream;
}
std::istream & operator>>(std::istream & stream, integer & rhs){
uint8_t base;
if (stream.flags() & stream.oct)
base = 8;
else if (stream.flags() & stream.hex)
base = 16;
else
base = 10;
std::string in;
stream >> in;
rhs = integer(in, base);
return stream;
}
EDIT: Forgot to mention: This should be compiled with C++11 enabled
Link to working code: http://ideone.com/mYDLp