分数类溢出(C++)

Fraction class overflow (C++)

本文关键字:C++ 溢出      更新时间:2023-10-16

我为基本运算构建了一个普通的分数类。唯一的问题是,由于有大量的运算(我在做高斯消去),分子或分母都会溢出。

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

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

并确保您尽快简化("取消")分数!这样可以使分母和分子保持较小。因此,最大公约数可能是有意义的。

您可能会溢出/未溢出,因为您的100x100矩阵状况不佳。如果你没有使用部分旋转,你应该使用。

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

对需要约670000次算术运算的算法使用精确有理算术注定会失败。你怎么会有其他想法呢?如果你需要一个精确到10^-6的结果,那么就要精确到(哦,我不知道)10^-20,然后使用旋转。

众所周知,完整NxN矩阵a的LU分解(相当于无枢轴的高斯消去的行约简阶段)需要~2N³/3的乘法和除法。即使部分旋转,此操作计数也保持不变。

浮点运算在每一步都会产生舍入误差。消除步骤的"正向"误差分析并不能产生有用的精度估计,因为在最坏的情况下,舍入误差可能会呈指数级累积。然而,J.H.Wilkinson指出,"后向误差分析可以给出现实的估计,例如,对于正定矩阵或对角占优矩阵,其中通过具有完全枢轴的高斯消去法计算的解是待解系统的"适度"扰动的精确解(通常也是仅具有部分枢轴的情况)然后可以根据扰动的大小和矩阵的条件数来估计残差的大小,通常定义为A的范数与A的逆的范数的比率。如果A是奇异的,这是无限的,如果A接近奇异,那么任意大。如果条件数足够大,可以将扰动大小(通常是浮点运算的机器ε)放大为大于可接受的残差,则我们认为矩阵是病态的。否则,我们说A条件良好。

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

但是,精确的整数保留算法通常会导致条目的快速增长,从而导致溢出,即使矩阵在上述意义上是条件良好的。从Jordan(在计算矩阵逆而不是线性系统解的消去法版本中,Jordan的名字经常与高斯联系在一起)开始,人们就提出了各种策略来最小化条目的增长。W.Kahan给出了一个特别简洁的描述。一个任意精度的整数(或有理)实现将解决这个困难。

然而,这种精确的方法能否与稠密矩阵上的浮点运算相竞争似乎是值得怀疑的。如果像高斯消去法这样的直接方法没有达到所需的精度,则通过计算残差(将矩阵a乘以计算出的解,并从右侧的向量中减去它)来检查,然后用具有相同矩阵a但右侧对应于残差的线性系统再次求解校正项。如果高斯消去的归约阶段实际上是作为LU因子分解来完成的,那么只需要反求解阶段来求解迭代校正。

在必须从可用的浮点精度中挤出最佳精度的情况下,基于正交矩阵的直接方法是有用的(请参见Householder和Givens变换)。

底线是,线性系统的解决方案是一个经常被重新发明的轮子,几乎无法想象软件重用的更有力的理由。请参阅本演示的第三张幻灯片:"如何编写数值线性代数软件——不要!尽可能依靠现有的成熟软件库来执行数值线性代数计算。"