比较两个值的比率为1

时间:2016-07-19 17:50:20

标签: c while-loop

我正在通过基本的“C语言编程”一书工作。

我已经根据它编写了以下代码,以便计算数字的平方根:

#include <stdio.h>

float absoluteValue (float x)
{
    if(x < 0)
        x = -x;

    return (x);
}

float squareRoot (float x, float epsilon)
{

    float guess = 1.0;

    while(absoluteValue(guess * guess - x) >= epsilon)
    {
        guess = (x/guess + guess) / 2.0;
    }

    return guess;
}


int main (void)
{
    printf("SquareRoot(2.0) = %f\n", squareRoot(2.0, .00001));
    printf("SquareRoot(144.0) = %f\n", squareRoot(144.0, .00001));
    printf("SquareRoot(17.5) = %f\n", squareRoot(17.5, .00001));

    return 0;
}

本书中的一项练习表明,用于终止squareRoot()中的循环的当前标准不适合在计算非常大或非常小的数字的平方根时使用。

程序应该将两个值的比率与1进行比较,而不是比较x的值和猜测^ 2的值之间的差异。该比率越接近1,正方形的近似越准确根

如果比率只是猜测^ 2 / x,那么我的代码不应该在while循环中:

guess = (x/guess + guess) / 2.0; 

替换为:

guess = ((guess * guess) / x ) / 1 ; ? 

这个编译但没有任何内容打印到终端。当然,我正在做的是练习所要求的内容吗?

5 个答案:

答案 0 :(得分:2)

根据您的实施情况,计算比例(猜测*猜测/ x)可能高于或低于1。同样,您的误差范围(百分比)将为absoluteValue((guess * guess / x) - 1)* 100

他们想要检查的是平方根的接近程度。通过平算你得到的数字并将它除以你所取的数字你的平方根只是检查你与原始数字的接近程度。

Example: 
sqrt(4) = 2 
2 * 2 / 4 = 1 (this is exact so we get 1 (2 * 2 = 4 = 4))
margin of error = (1 - 1) * 100 = 0% margin of error

Another example:
sqrt(4) = 1.999 (lets just say you got this)
1.999 * 1.999 = 3.996
3.996/4 = .999 (so we are close but not exact)

To check margin of error:
.999 - 1 = -.001
absoluteValue(-.001) = .001
.001 * 100 = .1% margin of error

答案 1 :(得分:0)

应用小代数怎么样?您目前的标准是:

| guess 2 - x | &gt; = epsilon

你在其他地方假设 guess 非零,所以将其转换为

是代数安全的

| 1 - x / guess 2 | &gt; = epsilon / guess 2

epsilon 只是一个控制匹配需要的接近的参数,上面的重构表明它必须用 guess 2 以获得所有评估的等效精度。但当然这是不可能的,因为 epsilon 是一个常数。事实上,这正是 x 偏离1时原始标准变得不那么有效的原因。

让我们改为编写替代表达式

| 1 - x / guess 2 | &gt; = delta

这里, delta 表示在1附近浮点值的间距方面所需的精度,这与有时称为“机器epsilon&#34”的固定数量有关。 ;。您可以通过选择 delta 直接选择所需的精度,只要没有算术运算溢出,您将获得所有x的相同精度。

现在只需将其转换回代码。

答案 2 :(得分:0)

建议不同的观点。

作为此方法guess_next = (x/guess + guess) / 2.0;,一旦初始近似值在邻域中,bits of accuracy doubles的数量。示例log2(FLT_EPSILON)约为-23,因此需要进行6次迭代。 (想想23,12,6,3,2,1)

使用guess * guess的问题在于,对于非零x,它可能会消失,变为0.0或无穷大。

形成高质量的初步猜测:

assert(x > 0.0f);
int expo;
float signif = frexpf(x, &expo);
float guess = ldexpf(signif, expo/2);

现在迭代N次(例如6次),(N基于FLT_EPSILONFLT_DECIMAL_DIGFLT_DIG。)

for (i=0; i<N; i++) {
    guess = (x/guess + guess) / 2.0f;
}

通过避免昂贵的终止条件计算,可以节省额外迭代的成本。

答案 3 :(得分:0)

如果代码想比较最接近1.0f的a/b

只需使用一些epsilon因子,如1或2。

float a = guess;
float b = x/guess;
assert(b);
float q = a/b;
#define FACTOR (1.0f /* some value 1.0f to maybe 2,3 or 4 */) 
if (q >= 1.0f - FLT_EPSILON*N && q <= 1.0f + FLT_EPSILON*N) {
  close_enough();
}

答案 4 :(得分:0)

数值分析的第一课:对于浮点数x+y,可能存在较大的相对误差,尤其是当总和接近于零时,x*y的相对误差非常有限。