使用 BCD 格式进行数字除法

发布于 2024-11-17 16:11:27 字数 472 浏览 6 评论 0原文

我有两个包含(解压的)BCD 数字的 std::deque 对象。每个字节是一个 BCD 数字。大小不受限制,但 MAX_SCALE = 10,因此 1 / 3 应得到 0.3333333333。对于这两个对象,都会保存比例和符号:

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

每个数字对象在计算前缩放为 0,10.34 / 2.1 缩放为 1034 / 210,并记录最高比例 (2) 以便稍后重新缩放。

计算第三个数值对象的商的最快方法是什么?

我已经实现了加法、减法和乘法,但是我找不到如何实现(快速)除法(具有无限位数)的良好解释。

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).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

亽野灬性zι浪 2024-11-24 16:11:27

您可以使用牛顿法求 1 / a。

令 f(x) = 1 / x - a,您想要找到 f^{-1}(0)。

然后

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

收敛到f^{-1}(0)。 我们

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

因此

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

收敛到 1/a。您使用以下标准测试收敛性:

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

您大致需要 log n 乘法才能收敛。如果乘法为 O(n^2),则对于大数来说,这比长除法慢(O(n^2) 与 O(n^2 log n))。尽管如此,它实施起来很快,而且在实践中也不错。事实上,一些处理器使用该方案的变体来求逆并执行除法。请注意,如果您有更好的乘法算法,那么牛顿方法将渐近优于长除法。

作为对 x_0 的第一个猜测,您可以将除最高有效数字之外的所有数字设置为零,并直接找到其倒数。

示例:a = 3425,23。第一个猜测:1 / a ~ 1 / 3000 ~ 0.0033333333

顺便说一句,迭代

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

将收敛到 1 / sqrt(a) (采用两个前导数字和一个小查找表作为初始猜测)。

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).

四叶草在未来唯美盛开 2024-11-24 16:11:27

执行整数算术中的所有操作:要计算 10.34 / 2.1,您需要计算 10340000000000 / 2100,然后除以 10^10。要计算 10340000000000 / 2100,您只需购买 Knuth vol 2,正如 Alexandre C 已经提到的那样。 (这不是你会后悔的事情!)我认为牛顿方法在这里不适用,除非你的数字非常大。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文