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; } }