开发者

Numeric division using BCD format

I've two std::deque objects containing (unpacked) BCD numbers. Each byte is one BCD digit. The size is not limited, but there is a MAX_SCALE = 10, so 1 / 3 should result in 0.3333333333. For both objects, the scale and sign is saved:

class Numeric
{
   std::deque<uint8_t> m_digits;
   size_t m_scale; // indicates how many digits after "."
   bool sign; // true = positive, false = negative
};

Each Numeric object is scaled to 0 before calculation, 10.34 / 2.1 is scaled to 1034 / 210 and the highest scale (2) is recorded for rescale back later.

What is the fastest method to calculate the quotient into a third Numeric object?

I've already implemented addition, substraction und multiplication, but I can't find a good 开发者_如何学运维explanation how to implement (fast) divison (with an unlimited number of digits).


You can use Newton's method to find 1 / a.

Let f(x) = 1 / x - a, you want to find f^{-1}(0).

Then

x_{n + 1} = x_n - f(x_n) / f'(x_n)

converges to f^{-1}(0). This gives us

x_{n + 1} = x_n - (1 / x_n - a) / (-1 / x^2)

therefore

x_{n + 1} = x_n * (2 - a * x_n)

converges to 1 / a. You test convergence with the criterion

if (|x_{n + 1} - x_n| < tolerance) then stop

You roughly need log n multiplications to converge. If multiplications are O(n^2), this is slower than long division for large numbers (O(n^2), vs O(n^2 log n)). Nevertheless, it is quick to implement and not so bad in practice. In fact, some processors use a variant of this scheme to find inverses and perform divisions. Note that if you have a better multiplication algorithm, then Newton's method outperforms long division asymptotically.

As a first guess for x_0, you can set all but the most significant digit to zero, and find its inverse directly.

Example: a = 3425,23. First guess : 1 / a ~ 1 / 3000 ~ 0.0033333333

As an aside, the iteration

x_{n + 1} = x_n * (3 - a * x_n^2)

will converge to 1 / sqrt(a) (take two leading digits and a small lookup table for the initial guess).


Do everything in integer arithmetic: to calculate 10.34 / 2.1, you want to calculate 10340000000000 / 2100 and then divide by 10^10. And to calculate 10340000000000 / 2100, you only need to purchase Knuth vol 2, as Alexandre C already mentioned. (This is not something that you will ever regret!) I don't think Newton's method is applicable here, unless your numbers are very large.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜