[英]Comparing the ratio of two values to 1
我正在通過基本的“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 ; ?
這個編譯但沒有打印到終端。 當然,我正在做的是練習所要求的?
根據您的實現,計算比率(可以猜測/猜測/ 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
應用小代數怎么樣? 您目前的標准是:
| 猜 2 - x | > = epsilon
您在其他地方假設猜測非零,因此將其轉換為代數是安全的
| 1 - x / guess 2 | > = epsilon / guess 2
epsilon只是一個控制匹配所需距離的參數,上面的重構表明它必須以猜測 2附近的浮點間距表示,以產生所有評估的等效精度。 但當然這是不可能的,因為epsilon是一個常數。 事實上,這正是原始標准在x偏離1時效果較差的原因。
讓我們改寫替代表達式
| 1 - x / guess 2 | > = delta
這里, delta表示在1附近的浮點值的間隔方面的期望精度,其與有時稱為“機器epsilon”的固定量相關。 您可以通過選擇delta直接選擇所需的精度,只要沒有算術運算溢出,您將獲得所有x
的相同精度。
現在只需將其轉換回代碼。
建議不同的觀點。
正如這個方法guess_next = (x/guess + guess) / 2.0;
一旦初始近似值在鄰域中 , 精度位數就會翻倍 。 示例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_EPSILON
, FLT_DECIMAL_DIG
或FLT_DIG
。)
for (i=0; i<N; i++) {
guess = (x/guess + guess) / 2.0f;
}
通過避免昂貴的終止條件計算,可以節省額外迭代的成本。
如果代碼想比較最接近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();
}
數值分析的第一課:對於浮點數x+y
可能存在較大的相對誤差,尤其是當和接近於零時, x*y
相對誤差非常有限。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.