【发布时间】:2014-03-20 22:30:41
【问题描述】:
我有一个这样的循环:
for(uint64_t i=0; i*i<n; i++) {
这需要每次迭代都进行一次乘法运算。如果我可以在循环之前计算 sqrt,那么我可以避免这种情况。
unsigned cut = sqrt(n)
for(uint64_t i=0; i<cut; i++) {
在我的情况下,如果 sqrt 函数向上舍入到下一个整数是可以的,但如果它向下舍入就不行了。
我的问题是:sqrt 函数在所有情况下都足够准确吗?
编辑:让我列出一些案例。如果 n 是一个完美的正方形,那么 n = y^2 我的问题是 - 所有 n 都是 cut=sqrt(n)>=y 吗? 如果 cut=y-1 则有问题。例如。如果 n = 120 并且 cut = 10 没关系,但如果 n=121 (11^2) 并且 cut 仍然是 10,那么它将不起作用。
我首先担心的是浮点数的小数部分只有 23 位和双 52,因此它们无法存储某些 32 位或 64 位整数的所有数字。但是,我认为这不是问题。假设我们想要某个数字 y 的 sqrt,但我们不能存储 y 的所有数字。如果我们让我们可以存储的 y 的分数为 x,我们可以写成 y = x + dx,那么我们要确保我们选择的任何 dx 都不会将我们移动到下一个整数。
sqrt(x+dx) < sqrt(x) + 1 //solve
dx < 2*sqrt(x) + 1
// e.g for x = 100 dx < 21
// sqrt(100+20) < sqrt(100) + 1
浮点数可以存储 23 位,所以我们让 y = 2^23 + 2^9。这已经足够了,因为 2^9
unsigned xi = -1-1;
printf("%u %u\n", xi, (unsigned)(float)xi); //4294967294 4294967295
printf("%u %u\n", (unsigned)sqrt(xi), (unsigned)sqrtf(xi)); //65535 65536
由于 float 不能存储 2^31-2 和 double 的所有数字,所以它们可以得到 sqrt 的不同结果。但是 sqrt 的浮点版本要大一个整数。这就是我要的。对于 64 位整数,只要 double 的 sqrt 总是向上取整就可以了。
【问题讨论】:
-
听起来像是过早的优化 - 是什么让您认为每次迭代的单个整数乘法在您的循环中是一个很大的开销?
-
ceil()应该可以帮助您。它在数学图书馆。确保传递一个浮点数或双精度数,因为整数除法将模拟floor()函数。 -
@PaulR。这是一个非常紧密的循环。我在做审判师。如果我这样做,例如
i<n/i比i*i<n慢两倍。但是您可能是对的,i*i<n的性能还可以,但它还有其他问题。它对于大 n 溢出并进入无限循环,它不适用于#pragma omp parallel for。 -
@PaulR,这里有更多关于我在做什么的详细信息stackoverflow.com/questions/22556599/…
-
如果你用它来计算试除循环的最大尺寸,那么只要加一个就可以了。
标签: c math floating-point