我正在开发一个应用程序,用于解决涉及圆和线(Constructable Numbers)的二维欧几里德几何中的二次约束,并以图形方式表示结果。我发现this paper在二叉树中表示这些问题,但我遇到了一个实现问题:
我需要比较a + b*sqrt(c)
形式的数字,以获得小于,大于和相等的标准关系运算。我的应用的c
值仅限于2
,3
,5
,6
,10
,15
,或30
。例如(类似C的伪代码,^
是“对于运算符的幂”:
boolean CompareConstructibleNumbers(int a1, b1, c1, a2, b2, c2)
{
return a1plusb1sqrtc1_is_greater_than_a2plusb2sqrtc2 =
4 * ((a1 - a2)^2) * (b1^2) * c1
> ((b2^2) * c2 - (b1^2) * c1 - (a1 - a2)^2)^2;
// Not sure if I have the direction right for >
}
这个天真的实现要求我多次乘法,所以32位整数变成64位整数,然后变成128位等等。我不想在我的实现中使用自定义BigInteger来存储临时值仅用于比较。
我也不想使用浮点数,并希望避免在尝试直接计算sqrt(c)
作为浮点数时出现舍入错误的风险。我需要精确计算这个应用程序,不一定是无限精度,但我想避免舍入误差并确保正确的结果。
如何在不需要巨大的中间整数值的情况下比较a + b * sqrt(c)
形式的可构造数字?我a
和b
的初始值在32位范围内。
**** **** UPDATE 谢谢大家的回复。继续追求连续分数的建议,我能够使用Fundamental Recurrence Formulas为平方根生成任意精确的近似值。
我还发现this paper讨论了实数近似乘法与整数定点表示的误差累积。幸运的是,我感兴趣的所有平方根的整数部分最多为6(仅需要3位),因此我有很多位可用于表示近似的小数部分。为了乘以32位整数,我需要Q3.32位的最小定点近似值,以便在乘法后将误差保持为1位。
因此,虽然53位精度double
足以为平方根存储足够精确的近似值,但在乘以32位整数后存储结果是不够的,因为这需要最小值精度为67位,以最大限度地减少错误。使用64位整数(比如Q16.48)中的c
和32位整数b
的定点表示,我打算使用96或128位数的多字算法在没有足够错误的情况下进行比较以甩掉结果。我相信这对于比较仅使用这7个平方根的可构造数字来说足够准确,但我对第二个意见感兴趣。有什么想法吗?
答案 0 :(得分:3)
我不认为有一个公式可以让你保持64位以进行精确比较,假设你的值使用完整的32位。我认为问题是a + b * sqrt(c)形式的数字在实数中是密集的(假设c不是正方形),所以你得到非常微妙的比较,需要很多精度。因此,你基本上需要通过平方来消除平方根,这将使用3次乘法。
在这种情况下,BigInt实现实际上并不是那么糟糕,因为您只需要实现乘法,加法,减法和比较。这些可以在很少的代码行中有效地实现。通常情况下,它的划分很难实现。此外,您知道您的数字永远不会溢出带有两个64位单元的数组,因此您实际上不需要跟踪产品中的位数。
编辑:关于Thomas和Nemo对此的评论所建议的双打的使用,实际上很容易通过使用连续分数表示在32 ^ { - 53}的sqrt(2)内找到使用32位整数的近似值