Exemplo n.º 1
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;
    }
}