在简单的素性检查中,通常的做法是检查从2到max = floor(sqrt(n))
的除数。
在IEEE定义的浮点运算(比如32位和64位数)中,浮点错误是否会使未命中的因素略大于max
?
例如,max = floor(sqrt(REALLY_BIG_N))
,但(max + 1) * something = REALLY_BIG_N
。
如果我的问题不完全清楚,请发表评论。
(请注意,我对这里的primality检查备选方案不感兴趣,或者通过使用sqrt
来避免使用x * x < n
- 我的问题实际上是关于它是否适用于IEEE浮点运算。)
答案 0 :(得分:3)
没有
我认为max+1
可以表示为浮点值(它不是很大,超出了浮点格式可以表示区间中所有整数的区间)。
我还假设something
中的(max+1) * something
是大于max
的整数。否则,先前在寻找除数时会发现它(或更小的因子)。这意味着 n ≤( max +1)•( max +1)。
正确实现的sqrt
返回最接近其参数平方根的可表示值。因此,如果n
的数学平方根至少为x+1
,则sqrt(n)
必须返回x+1
或更高;它无法返回x
,因为x
距离平方根比x+1
更远。因此,max = floor(sqrt(n))
的结果不小于floor的数学值(sqrt( n ))。
对于IEEE-754 64位二进制(以下称double
),最多2 53 的所有整数都是可表示的。 2 53 +1是第一个不可表示的整数。因此,上面告诉我们sqrt(n)
足以满足所有n
,但不包括(2 53 +1) 2 。当然,许多大的整数在double
中都不能完全表示,所以你不能将它们传递给sqrt
。
答案 1 :(得分:3)
补充Eric Postpischil的回答:是的,然后再没有。这取决于floor(sqrt(n))
非常大的情况下我们将如何解释n
。
正如在Eric的回答中,让我们假设IEEE 754二进制64格式浮点和正确舍入sqrt
,通常采用圆形连接到均匀舍入模式。我还假设访问n
的任意精度整数类型。
第一种解释:假设允许n
采用任何整数值,floor(sqrt(n))
将被解释为floor(sqrt(convert_to_double(n)))
。然后,n >= 2^1024 - 2^970
会立即出现问题,因为此时convert_to_double
会溢出。 (我假设convert_to_double
也是正确的四舍五入。)从另一端开始,Eric的答案已经表明我们很擅长但不包括n = (2^53 + 1)^2
,正如他所说,{{ 1}}是一个问题案例:n = (2^53 + 1)^2
的值为convert_to_double(n)
,一个小于真值,2^106 + 2^54
将向下舍入为sqrt(convert_to_double(n))
,这意味着您的试用版除法函数将错过因子2^53
。但是,考虑到2^53 + 1
可以被2^53 + 1
和3
整除,试验部门很可能已经发现了其他因素,因此缺少107
可能不是问题。在这种情况下,2^53+1
应被视为第一个问题案例。 (n = (2^53 + 5)^2
是素数。)
第二种解释:假设2^53 + 5
被约束为一个正整数,它可以完全表示为double。然后一个简洁的事实是n
的任何除数也必须完全可以表示为双精度:n
可以用n
形式写成一些非负指数m•2^e
和奇数e
的整数m
,m < 2^53
的任何除数都可以n
的形式写成d•2^f
d
的{{1}}和exponent { {1}} m
。但是现在如果f
是0 <= f <= e
的除数小于x
的精确平方根,n
可以完全表示为double,那么 nearest < / em> n
的平方根的可表示的double必须大于或等于x
。因此,最高n
的试验分区例程不能错过x
。
只是为了好玩:在这里,我们只担心floor(sqrt(n))
的值x
给出的值太小。n
如果您对floor(sqrt(n))
给出的值太大的情况感兴趣,那么第一个示例会在floor(sqrt(n))
之前发生很多。 (证明作为练习留下。)
当然,这完全是学术性的:如果您正在进行数字大于n = (2^26 + 1)^2 - 1
的试验分组,那么您将等待长时间来获得任何结果。 ..
答案 2 :(得分:1)
在处理素数时没有理由使用浮点运算。永远!您应该循环直到max
,其中d * d > n
是试验除数,而d
是正在测试的数字,而不是计算n
。如果必须计算平方根,编写自己的函数,只使用整数运算;牛顿的方法与整数完美匹配。
编辑:这是一个计算整数平方根的简单函数:给定一个整数n
,isqrt(n)
返回*x
不超过的最大整数x * x
n
;所有除法都是整数除法,它会截断任何小数余数:
function isqrt(n)
x := n
y := (x + n // x) // 2
while y < x
x := y
y := (x + n // x) // 2
return x