void ShiftLeftTests::should_correctly_shift_by_large_number() { BigNumber sut = BigNumber("4294967295") << BigNumber("510"); std::string sutStr = sut.toString(); assert(sut.toString() == "14396524139186276442508073949701635698831569246696291770774319487926989897218320177502543451331982168338021057104758899847644938664143288301840606092160112084910080"); }
/// Return a BigNumber object. // Will create a BigNumber object out of a stored string, at given precision (in decimal) - that's why the aPrecision argument must be here - but only if no BigNumber object is already present BigNumber* LispNumber::Number(LispInt aBasePrecision) { if (!iNumber) { // create and store a BigNumber out of string assert(iString.ptr()); RefPtr<LispString> str; str = iString; // aBasePrecision is in digits, not in bits, ok iNumber = NEW BigNumber(str->c_str(), aBasePrecision, BASE10); } // check if the BigNumber object has enough precision, if not, extend it // (applies only to floats). Note that iNumber->GetPrecision() might be < 0 else if (!iNumber->IsInt() && iNumber->GetPrecision() < (LispInt)digits_to_bits(aBasePrecision, BASE10)) { if (iString) {// have string representation, can extend precision iNumber->SetTo(iString->c_str(),aBasePrecision, BASE10); } else { // do not have string representation, cannot extend precision! } } return iNumber; }
BigNumber& BigNumber::operator-=(const BigNumber& rhs) { if(_sign && rhs._sign) { if(moduloComparisonMore(rhs)) { subtractionMethod(rhs); _sign = true; } else { *this = BigNumber(rhs).subtractionMethod(*this); _sign = false; } } else if(_sign && !rhs._sign) { addMethod(rhs); _sign = true; } else if(!_sign && rhs._sign) { addMethod(rhs); _sign = false; } else if(!_sign && !rhs._sign) { if(moduloComparisonMore(rhs)) { subtractionMethod(rhs); _sign = false; } else { *this = BigNumber(rhs).subtractionMethod(*this); _sign = true; } } _stringFormat = NULL; return *this; }
BigNumber BigNumber::operator%(const BigNumber &y) const { BigNumber l; for (auto i = 0u; i < data_.size(); ++i) { l.data_.push_front(data_[data_.size() - i - 1]); auto div = findDiv(l, y); l = l - y * BigNumber(div); } return l; }
int main(void) { HAL_Init(); SystemClock_Config(); PCD8544Init(); while(1) { ClearDisplayBuffer(); //erase BigNumber(msTicks); //draw PCD8544Update(); //display HAL_Delay(1000); } }
BigNumber BigNumber::operator ~() const { //Corner case: number is zero. if(this->is_zero()) { return BigNumber("1"); } BigNumber result; Block* current_block = NULL; int32_t offset = 0, max_offset = -1; element_type operation_result = 0; uint32_t zero_elements = 0; for(BigNumberIterator it = this->get_lowest_byte(); it != ++this->get_highest_byte(); ++it) { operation_result = ~(*it); if(operation_result == 0) { zero_elements++; continue; } for(int i = 1; i <= zero_elements; ++i) { if(offset > max_offset) { current_block = &result.push_back_new_block(); offset = 0; max_offset = current_block->get_size() - 1; } current_block->get_bits_array()[offset++] = 0; } if(offset > max_offset) { current_block = &result.push_back_new_block(); offset = 0; max_offset = current_block->get_size() - 1; } current_block->get_bits_array()[offset++] = operation_result; current_block->trailing_zeros = current_block->get_size() - offset; } return result; }
BigNumber BigNumber::operator <<(const BigNumber& x) const { //Corner cases: operand or swifted number is zero. if(this->is_zero()) { return BigNumber(); } if(x.is_zero()) { return *this; } BigNumber result(*this), counter(x); BigNumberIterator highest_byte = result.get_highest_byte(), lowest_byte = result.get_lowest_byte(); uint8_t shift_value = BitShiftsAlgorithms::expand_number_at_lowest_bytes_end(result, counter); BitShiftsAlgorithms::expand_number_at_highest_bytes_end(result, highest_byte, shift_value); BitShiftsAlgorithms::shift_left_number(result, highest_byte, lowest_byte, shift_value); return result; }
unsigned BigNumber::findDiv(const BigNumber ÷nd, const BigNumber &divisor) const { unsigned first = 0; unsigned last = BASE; unsigned it; int64_t count, step; count = last - first; while (count > 0) { it = first; step = count / 2; it += step; if (!(dividend < BigNumber(it) * divisor)) { first = ++it; count -= step + 1; } else count = step; } return first - 1; }
BigNumber() { *this=BigNumber(string("0")); }
void BigNumber::subtract(const BigNumber& minuend, const BigNumber& subtrahend, BigNumber& result) { //Corner case: subtrahend is zero. if(subtrahend.is_zero()) { result = minuend; return; } //Equality check is required to subtract smaller number from larger. equality_check compare_result = minuend.compare_to(subtrahend); //Corner case: equal numbers. if(compare_result == EQUAL) { result = BigNumber(); return; } //Set result sign. if(compare_result == SECOND_BIGGER) { result.is_negative = true; } //Remember relation between subtracted numbers. const BigNumber& greater_number = (result.is_negative == false) ? minuend : subtrahend; const BigNumber& smaller_number = (&greater_number == &minuend) ? subtrahend : minuend; //Set iterators to lowest bytes. BigNumberIterator greater_it = greater_number.get_lowest_byte(); BigNumberIterator smaller_it = smaller_number.get_lowest_byte(); //Latest subtraction value. ex_element_type operation_result = 0; //Offset in last block where result may be stored. int32_t offset = 0, max_offset = -1; //Current block pointer - to avoid calls to list every time. Block* block = NULL; //Borrow flag - indicates if current computation is using "borrowed" values. bool borrow = false; uint64_t zero_elements = 0; //Subtract smaller number from equal subset of higher number. for(;smaller_it != ++smaller_number.get_highest_byte(); ++smaller_it, ++greater_it, operation_result = 0) { // TODO: AG: Should not count ++smaller_number.get_highest_byte() every time //Copy current byte from greater number to result buffer. operation_result = *greater_it; if(borrow) { if(*greater_it > 0) { //Decrement value if this is the digit from which the borrow is taken (first non-zero digit before the loan taker). --operation_result; borrow = false; } else { //This digit is also beneficient of loan, enjoy it. operation_result += ELEMENT_MAX; } } //Enter "borrow mode" and take extra value. if(operation_result < *smaller_it) { borrow = true; operation_result += ELEMENT_MAX + 1; } //Actual subtraction takes place here. operation_result -= *smaller_it; //Zero-results are counted, but not immedietaly appended to number. //This is to avoid redundant blocks with arrays filled with zeros at the end of chain. if(operation_result == 0) { ++zero_elements; continue; } //If the result is non-zero, insert all preceeding zeros to number. for(;zero_elements > 0; --zero_elements, ++offset) { if(offset > max_offset) { block = &result.push_back_new_block(); offset = 0; max_offset = block->get_size() - 1; } block->get_bits_array()[offset] = 0; } if(offset > max_offset) { block = &result.push_back_new_block(); offset = 0; max_offset = block->get_size() - 1; } //Insert non-zero result into the chain. block->get_bits_array()[offset++] = (element_type)operation_result; block->trailing_zeros = block->get_size() - offset; } //Rewrite the rest of larger number into result. for(;greater_it != ++greater_number.get_highest_byte(); ++greater_it) { // TODO: AG: Should not count ++greater_number.get_highest_byte() every time //Copy current byte from greater number to result buffer. operation_result = *greater_it; if(borrow) { if(*greater_it > 0) { //Decrement value if this is the digit from which the borrow is taken (first non-zero digit before the loan taker). --operation_result; borrow = false; } else { //This digit is also beneficient of loan, enjoy it. operation_result += ELEMENT_MAX; } } //Zero-results are counted, but not immedietaly appended to number. //This is to avoid redundant blocks with arrays filled with zeros at the end of chain. if(operation_result == 0) { ++zero_elements; continue; } //If the result is non-zero, insert all preceeding zeros to number. for(;zero_elements > 0; --zero_elements, ++offset) { if(offset > max_offset) { block = &result.push_back_new_block(); offset = 0; max_offset = block->get_size() - 1; } block->get_bits_array()[offset] = 0; } if(offset > max_offset) { block = &result.push_back_new_block(); offset = 0; max_offset = block->get_size() - 1; } //Insert non-zero result into the chain. block->get_bits_array()[offset++] = (element_type)operation_result; block->trailing_zeros = block->get_size() - offset; } }
void BigNumber::add(const BigNumber& arg1, const BigNumber& arg2, BigNumber& result) { equality_check ec; ex_element_type current_sum = 0; element_type carry = 0; if (arg1.get_actual_size() > arg2.get_actual_size()) { result = BigNumber(arg1); ec = FIRST_BIGGER; } else { result = BigNumber(arg2); ec = SECOND_BIGGER; } BigNumberIterator larger_it = (ec == FIRST_BIGGER) ? arg1.get_lowest_byte() : arg2.get_lowest_byte(); BigNumberIterator smaller_it = (ec == FIRST_BIGGER) ? arg2.get_lowest_byte() : arg1.get_lowest_byte(); std::list<Block>::iterator it; for (it = result.blocks.begin(); it != result.blocks.end(); ++it) { it->trailing_zeros = it->elements; } BigNumberIterator result_it = result.get_lowest_byte(); while (smaller_it != ++smaller_it.number.get_highest_byte()) { current_sum = (ex_element_type)*smaller_it + (ex_element_type)*larger_it + (ex_element_type)carry; *result_it = (element_type)current_sum; if ((element_type)current_sum != 0) { (*result_it.get_block_iterator()).trailing_zeros = (*result_it.get_block_iterator()).get_size() - 1 - result_it.get_offset(); } carry = CARRY_SHIFT(current_sum); ++smaller_it; ++larger_it; ++result_it; } while (larger_it != larger_it.number.end()) { // TODO: KK: Don't add trailing zeros (check if iterator reaches actual size) current_sum = *larger_it + carry; *result_it = (element_type)current_sum; if ((element_type)current_sum != 0) { (*result_it.get_block_iterator()).trailing_zeros = (*result_it.get_block_iterator()).get_size() - 1 - result_it.get_offset(); } carry = CARRY_SHIFT(current_sum); ++larger_it; ++result_it; } if (carry != 0) { // TODO: KK: Corner case, should be tested --result_it; Block& block = result.push_back_new_block(); ++result_it; *result_it = (element_type)carry; --block.trailing_zeros; } }
void ShiftLeftTests::should_correctly_shift_when_last_byte_has_available_space() { BigNumber one_bit_before = BigNumber("2097151") << BigNumber("2"); assert(one_bit_before.toString() == "8388604"); }
BigNumber BigNumber::operator ^(const BigNumber& x) const { //Corner cases to avoid problems with zero-operands. if(this->is_zero() && x.is_zero()) { return BigNumber(); } else if(this->is_zero()) { return BigNumber(x); } else if(x.is_zero()) { return BigNumber(*this); } BigNumber result = BigNumber(); //Determine which operand is smaller. If operands are of the same size, it doesn't matter. const BigNumber& smaller_number = x.get_actual_size() <= this->get_actual_size() ? x : *this; const BigNumber& greater_number = &smaller_number == this ? x : *this; //Iterators to currently XORed elements. BigNumberIterator smaller_it = smaller_number.get_lowest_byte(); BigNumberIterator greater_it = greater_number.get_lowest_byte(); //Counter of subsequent elements with zero value. uint64_t zero_elements = 0; //Latest XOR result. element_type operation_result = 0; //Offset in last block where result may be stored. int32_t offset = 0, max_offset = -1; //Current block pointer - to avoid calls to list every time. Block* block = NULL; //XORs smaller number with equal it's matching subset from greater number. for(;smaller_it != ++smaller_number.get_highest_byte(); ++smaller_it, ++greater_it) { operation_result = *smaller_it ^ *greater_it; if(operation_result == 0) { ++zero_elements; continue; } for(;zero_elements > 0; --zero_elements, ++offset) { if(offset > max_offset) { block = &result.push_back_new_block(); offset = 0; max_offset = block->get_size() - 1; } block->get_bits_array()[offset] = 0; } if(offset > max_offset) { block = &result.push_back_new_block(); offset = 0; max_offset = block->get_size() - 1; } block->get_bits_array()[offset++] = operation_result; block->trailing_zeros = block->get_size() - offset; } //XORs remaining part of greater number with zeros ("zero-padding from left" smaller number). for(;greater_it != ++greater_number.get_highest_byte(); ++greater_it) { operation_result = 0 ^ *greater_it; if(operation_result == 0) { ++zero_elements; continue; } for(;zero_elements > 0; --zero_elements, ++offset) { if(offset > max_offset) { block = &result.push_back_new_block(); offset = 0; max_offset = block->get_size() - 1; } block->get_bits_array()[offset] = 0; } if(offset > max_offset) { block = &result.push_back_new_block(); offset = 0; max_offset = block->get_size() - 1; } block->get_bits_array()[offset++] = operation_result; block->trailing_zeros = block->get_size() - offset; } return result; }
// constructor BigNumber::BigNumber() { BigNumber(0); }
BigNumber number(Word* p) const { return BigNumber(p + stateWords); }
void ShiftLeftTests::should_shift_by_nonmultiple_of_byte() { BigNumber shift_by_multiple_of_8_bytes = BigNumber("43981") << BigNumber("14"); assert(shift_by_multiple_of_8_bytes.toString() == "720584704"); }
void ShiftLeftTests::should_shift_by_multiple_of_byte() { BigNumber shift_by_multiple_of_8_bytes = BigNumber("43981") << BigNumber("16"); assert(shift_by_multiple_of_8_bytes.toString() == "2882338816"); }
void ShiftLeftTests::should_correctly_shift_when_there_is_exactly_required_amount_of_space() { BigNumber number_full = BigNumber("2097151") << BigNumber("3"); assert(number_full.toString() == "16777208"); }
BigNumber BigNumber::operator |(const BigNumber& x) const { //Corner cases: one or more operands are zero. if(this->is_zero() && x.is_zero()){ return BigNumber(); } else if(x.is_zero()) { return *this; } else if(this->is_zero()) { return x; } BigNumber result = BigNumber(); //Determine which operand is smaller. If operands are of the same size, it doesn't matter. const BigNumber& smaller_number = x.get_actual_size() <= this->get_actual_size() ? x : *this; const BigNumber& greater_number = &smaller_number == this ? x : *this; //Iterators to currently ORed elements. BigNumberIterator smaller_it = smaller_number.get_lowest_byte(); BigNumberIterator greater_it = greater_number.get_lowest_byte(); //Latest XOR result. element_type operation_result = 0; //Offset in last block where result may be stored. int32_t offset = 0, max_offset = -1; //Current block pointer - to avoid calls to list every time. Block* block = NULL; //OR smaller number with equal it's matching subset from greater number. for(;smaller_it != ++smaller_number.get_highest_byte(); ++smaller_it, ++greater_it) { operation_result = *smaller_it | *greater_it; if(offset > max_offset) { block = &result.push_back_new_block(); offset = 0; max_offset = block->get_size() - 1; } block->get_bits_array()[offset++] = operation_result; if(operation_result != 0) { block->trailing_zeros--; } } //OR remaining part of greater number with zeros ("zero-padding from left" smaller number). for(;greater_it != ++greater_number.get_highest_byte(); ++greater_it) { operation_result = 0 | *greater_it; if(offset > max_offset) { block = &result.push_back_new_block(); offset = 0; max_offset = block->get_size() - 1; } block->get_bits_array()[offset++] = operation_result; if(operation_result != 0) { block->trailing_zeros--; } } return result; }
BigNumber BigNumber::operator &(const BigNumber& x) const { //Corner case: both operands are zeros. Return zero. if(this->is_zero() || x.is_zero()) { return BigNumber(); } BigNumber result = BigNumber(); //Number of iterations, minimal size of operands. uint64_t iterations = std::min(this->get_actual_size(), x.get_actual_size()); { //Iterators to currently ANDed elements (bytes, values). BigNumberIterator this_iterator = this->get_lowest_byte(); BigNumberIterator x_iterator = x.get_lowest_byte(); //Counter of subsequent elements with zero value. uint64_t zero_elements = 0; //Latest AND result. element_type operation_result = 0; //Offset in last block where result may be stored. int32_t offset = 0, max_offset = -1; //Current block pointer - to avoid calls to list every time. Block* block = NULL; for(uint64_t i = 1; i <= iterations; ++i, ++this_iterator, ++x_iterator) { //Perform AND operation. operation_result = *this_iterator & *x_iterator; //Zero-results are counted, but not immedietaly appended to number. //This is to avoid redundant blocks with arrays filled with zeros at the end of chain. if(operation_result == 0) { ++zero_elements; continue; } //If the result is non-zero, insert all preceeding zeros to number. for(;zero_elements > 0; --zero_elements, ++offset) { if(offset > max_offset) { block = &result.push_back_new_block(); offset = 0; max_offset = block->get_size() - 1; } block->get_bits_array()[offset] = 0; } if(offset > max_offset) { block = &result.push_back_new_block(); offset = 0; max_offset = block->get_size() - 1; } //Insert non-zero result into the chain. block->get_bits_array()[offset++] = operation_result; block->trailing_zeros = block->get_size() - offset; } } return result; }
void ShiftLeftTests::should_correctly_shift_when_extra_element_must_be_allocated() { BigNumber one_bit_overflow = BigNumber("2097151") << BigNumber("4"); assert(one_bit_overflow.toString() == "33554416"); }