C++ 使用BCD格式的数字除法

C++ 使用BCD格式的数字除法,c++,numeric,C++,Numeric,我有两个std::deque对象,其中包含(未打包的)BCD编号。每个字节是一个BCD数字。大小不受限制,但有一个最大刻度=10,因此1/3应为0.3333。对于这两个对象,将保存比例和符号: class Numeric { std::deque<uint8_t> m_digits; size_t m_scale; // indicates how many digits after "." bool sign; // true = positive, false

我有两个std::deque对象,其中包含(未打包的)BCD编号。每个字节是一个BCD数字。大小不受限制,但有一个最大刻度=10,因此1/3应为0.3333。对于这两个对象,将保存比例和符号:

class Numeric
{
   std::deque<uint8_t> m_digits;
   size_t m_scale; // indicates how many digits after "."
   bool sign; // true = positive, false = negative
};
类数值
{
std::deque m_数字;
size\u t m\u scale;//表示“.”之后的位数
布尔符号;//真=正,假=负
};
每个数值对象在计算前缩放为0,10.34/2.1缩放为1034/210,并记录最高比例(2),以便稍后重新缩放

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


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

你可以用牛顿的方法找到1/a

设f(x)=1/x-a,您希望找到f^{-1}(0)

然后

收敛到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

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

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

你试过标准吗?它足够快吗?如果除数是一个非常大的数,那么它将是一个非常慢的方法。不是。这是O(n^2),IIRC,在Knuth第2卷中讨论了如何实现长除法。如果你已经有了乘法运算,请看我的答案,了解另一种实现除法的方法;它有一个反转指令,你用它与乘法一起除法。@马克:这是一种RISC计算机,它很可能像牛顿一样执行反转。谢谢你的例子。牛顿的方法只用于解1/x吗?@cytrinox:你可以用牛顿的方法解很多事情。请看维基百科的文章,了解一般理论。用它进行除法似乎令人惊讶,但从历史上看,它一直被用于任意精度的算术库(乘法通常是O(n logn))啊!解1/x就足够了:)但我不知道如何确定x_0。维基百科提到x_0=(48/17)-(32/17)*D,但这在我的测试中不是有效的结果。例如,如果D=6,x_0是什么?那么应该为公差选择哪个值呢?我认为问题的关键正是如何计算这样的整数长除法。我提到牛顿的方法是因为它不坏,而且很容易实现。正如你所说,克努斯有很多细节,但下一个最简单的东西(牛顿之后)是。@Alexandre:如果你是对的,为什么OP提到了最大刻度?在我看来,这似乎是第一件需要澄清的事情。
if (|x_{n + 1} - x_n| < tolerance) then stop
x_{n + 1} = x_n * (3 - a * x_n^2)