I am doing the BigInt class as a programming exercise. It uses a vector of 2 complemented ints signatures in base-65536 (so 32-bit multiplications do not overflow. I will increase the base as soon as I get it completely).
All basic mathematical operations are encoded with one problem: the division is very slow with the main algorithm that I was able to create. (This kind of works like a binary division for each digit of a private ... I will not publish it if someone does not want to see it ....)
Instead of my slow algorithm, I want to use Newton-Raphson to find the (offset) inverse, and then multiply (and shift). I think I have my own foundation: you give the formula (x1 = x0 (2 - x0 * divisor)) is a good initial guess, and then after a number of iterations x converges to mutual. This part seems easy enough ... but I am encountering some problems when trying to apply this formula to large integers:
Problem 1:
Because I work with integers ... well ... I cannot use fractions. This, apparently, leads to the fact that x always diverges (x0 * the divisor should be <2, it seems?). My intuition tells me that there must be some change in the equation that would allow him to work with integers (with some accuracy), but I'm really trying to figure out what it is. (My lack of math skills beats me here). It seems to me that I need to find some equivalent equation, where instead of d there is d * [base ^ somePower] ? Could there be some equation of type (x1 = x0 (2 - x0 * d)) that works with integers?
Problem 2:
When I use Newton's formula to find the inverse of some numbers, the result ends up as a small fraction below what should answer ... for example. when trying to find the inverse of 4 (in decimal):
x0 = 0.3 x1 = 0.24 x2 = 0.2496 x3 = 0.24999936 x4 = 0.2499999999983616 x5 = 0.24999999999999999999998926258176
If I represented numbers in base-10, I would like to get the result 25 (and remember that you need to shift the product by 2). With some feedback signals, such as 1/3, you can simply trim the result when you know that you have enough accuracy. But how can I get the correct response from the result above?
Sorry if this is too vague or I ask too much. I went through Wikipedia and all the research articles I could find on Google, but I feel like I'm banging my head on a wall. I appreciate any help anyone can give me!
...
Edit: Got an operation algorithm, although it is much slower than I expected. I really lost a lot of speed compared to my old algorithm, even by numbers with thousands of digits ... I still missed something. This is not a problem with multiplication, which is very fast. (I really use the Karatsuba algorithm).
For anyone interested, here is my current iteration of the Newton-Raphson algorithm:
bigint operator/(const bigint& lhs, const bigint& rhs) { if (rhs == 0) throw overflow_error("Divide by zero exception"); bigint dividend = lhs; bigint divisor = rhs; bool negative = 0; if (dividend < 0) { negative = !negative; dividend.invert(); } if (divisor < 0) { negative = !negative; divisor.invert(); } int k = dividend.numBits() + divisor.numBits(); bigint pow2 = 1; pow2 <<= k + 1; bigint x = dividend - divisor; bigint lastx = 0; bigint lastlastx = 0; while (1) { x = (x * (pow2 - x * divisor)) >> k; if (x == lastx || x == lastlastx) break; lastlastx = lastx; lastx = x; } bigint quotient = dividend * x >> k; if (dividend - (quotient * divisor) >= divisor) quotient++; if (negative)quotient.invert(); return quotient; }
And here is my (really ugly) old algorithm faster:
bigint operator/(const bigint& lhs, const bigint & rhs) { if (rhs == 0) throw overflow_error("Divide by zero exception"); bigint dividend = lhs; bigint divisor = rhs; bool negative = 0; if (dividend < 0) { negative = !negative; dividend.invert(); } if (divisor < 0) { negative = !negative; divisor.invert(); } bigint remainder = 0; bigint quotient = 0; while (dividend.value.size() > 0) { remainder.value.insert(remainder.value.begin(), dividend.value.at(dividend.value.size() - 1)); remainder.value.push_back(0); remainder.unPad(); dividend.value.pop_back(); if (divisor > remainder) { quotient.value.push_back(0); } else { int count = 0; int i = MSB; bigint value = 0; while (i > 0) { bigint increase = divisor * i; bigint next = value + increase; if (next <= remainder) { value = next; count += i; } i >>= 1; } quotient.value.push_back(count); remainder -= value; } } for (int i = 0; i < quotient.value.size() / 2; i++) { int swap = quotient.value.at(i); quotient.value.at(i) = quotient.value.at((quotient.value.size() - 1) - i); quotient.value.at(quotient.value.size() - 1 - i) = swap; } if (negative)quotient.invert(); quotient.unPad(); return quotient; }