分数类溢出(C ++)

时间:2011-06-28 14:50:05

标签: c++ math fractions

我为基本操作构建了一个普通的分数类。唯一的问题是,由于存在大量的操作(我正在进行高斯消除),因此分子或分母都会出现溢出。

我有100个方程式,所以100 x 100矩阵。最终结果需要精确到10 ^ -6。我该怎么办?

4 个答案:

答案 0 :(得分:2)

正如@Chris A在他的评论中已经建议的那样,我会使用任意精度整数作为分母和分子。您可以使用的示例实现是GNU MP Bignum

并确保尽快简化(“取消”)该分数!这使分母和分子变小。因此,greatest common divisor可能会引起人们的兴趣。

答案 1 :(得分:0)

您可能正在获得溢出/未流,因为您的100x100矩阵处于病态状态。如果你没有使用部分旋转,你应该是。

更好的选择是使用除高斯消除之外的其他东西。即使使用部分旋转,高斯消元仍然存在与病态矩阵相关的问题。一种替代方案是通过奇异值分解使用构造伪逆。使用SVD将矩阵A分解为UVW *形式。 A的伪逆是UV ^ { - 1} W *,其中V ^ { - 1}是对角矩阵V的伪逆。这很容易计算:只需找到每个对角元素的倒数,除了你使用的看似矛盾的1 /(小数)= 0。

答案 2 :(得分:0)

对需要~670000算术运算的算法使用精确有理算法注定要失败。你怎么能想到别的?如果您需要一个精确到10^-6的结果,那么工作精度为(哦,我不知道)10^-20,并使用旋转。

答案 3 :(得分:0)

众所周知,完整NxN矩阵A的LU decomposition(相当于没有旋转的高斯消除的行减少阶段)需要〜2N³/ 3次乘法和除法。即使部分旋转,此操作计数仍然存在。

浮点运算可能会在每一步都出现舍入错误。消除步骤的“前向”误差分析不会产生有用的准确度估计,因为在最坏的情况下,舍入误差可以指数累积。然而J.H. Wilkinson表示"backward error analysis可以给出真实的估计,例如对于正定或对角占优矩阵,其中通过高斯消除和完全旋转的计算解是要求解的系统的“适度”扰动的精确解(通常情况下也只是部分旋转)。然后可以根据扰动的大小和矩阵的条件数来估计残差的大小,通常定义为A的范数与A的倒数的比值。如果A是奇异的,那么这是无限的,如果A接近单数,那么任意大。如果条件数足够大以将扰动大小(通常是浮点运算的机器ε)放大到大​​于可接受的残差,我们说矩阵是病态的。否则我们说A的条件很好。

当然,一个想法是通过使用整数或有理数的精确算法来避免浮点运算的舍入误差。

但是,精确的整数保留算法通常会导致条目的快速增长并因此溢出,即使矩阵在上述意义上具有良好的条件。已经提出Various strategies用于最小化条目的增长,回到约旦(其名称通常与消除版本中的高斯相关联,其计算矩阵逆而不是线性系统的解)。 W. Kahan给出a particularly concise account。任意精度整数(或有理)实现都可以解决这个难题。

然而,这些精确的方法可能会与密集矩阵上的浮点运算竞争,这似乎令人怀疑。如果像高斯消除这样的直接方法没有达到所需的精度,那么通过计算残差(乘以矩阵A乘以计算解并从右侧矢量中减去)来检查,然后再次求解一个校正项。线性系统具有相同的矩阵A但右侧对应于残差。如果高斯消元的还原阶段实际上是作为LU分解完成的,则只需要后向相位来求解迭代校正。

如果必须从可用的浮点精度中挤出最佳精度,则基于正交矩阵的直接方法很有用(请参阅HouseholderGivens变换)。

底线是线性系统的解决方案是an oft-reinvented wheel,并且几乎无法想象软件重用的更强大的案例。参见the third slide of this presentation:“如何编写数值线性代数软件 - 请勿使用!尽可能依靠现有的成熟软件库进行数值线性代数计算。”