2

除算を使用せずに、正の実数の逆数を計算したかったのです。ニュートンラフソン法のさまざまなページを読んだ後、逆数を計算するために次のコードを実装しました。

#define PRECISION 0.1e-5
double inverse(double num) {
    double ans = num;
    while (ans * num > 1 + PRECISION || ans * num < 1 - PRECISION) {
        ans = ans * (2 - num * ans);
    }
    return ans;
}

さて、問題は、私は実際には逆の値を取得しないということです。ループは無限に続きます。

それで、私が最初に気づいたのは、の値が負になるということでした。私は、常に正のままであるようにansステートメントを追加しました。
if (ans < 0) ans *= -1;
ans

注意すべき2番目のポイント:の初期化の場合、=ans = 0.5のいくつかの値に対して正しい答えが得られます。num(1, 2, 3, 5)

したがって、私の仮定は、変数の不適切な初期化のために実装が機能していないということですans

それで、最後に私の質問:
1 。この方法を実際に使用して、すべての正の実数の逆数を計算できますか?
2.はいの場合、ニュートンラフソン法を使用するときに想定される初期値に必要な条件はありますか?
3.除算を使用せずに逆数を計算する他のより良い方法はありますか?

編集:

答えてくれてありがとう。それで、答えで述べたように、私はtoの初期値を変更しました、ansそしてPRECISIONそれは機能します!また、初期値はの特定の最大制限に適しているためnumans負になることはありません。したがって、最初に追加した負のチェック条件は必要ありません。

だから、これは動作するコードです(少なくとも私が与えた入力に対して動作します)。

double inverse(double num) {
    // Added to make it valid for all inputs.
    // For a too large number under the precision constraint, the answer is 0.
    if (num > 999999)
        return 0;
    double ans = PRECISION;
    while (ans * num > 1 + PRECISION || ans * num < 1 - PRECISION) {
        ans = ans * (2 - num * ans);
    }
    return ans;
}
4

2 に答える 2

4

(0, 2/num) から初期近似を選択する必要があります。2/num の反対側から選択すると、メソッドは収束しない可能性があります。近似は 0 をオーバーシュートし、数列は -∞ になる傾向があります。

間隔に到達するために、ans*(2-num*ans)符号が変わる場所を見てみましょう。2-num*ans < 0 の場合、または ans > 2/num の場合は負になります。したがって、最初ansは 2/num 未満にする必要があります。

適切な初期近似を選択できるようにするには、浮動小数点数がどのように表現されるかについて少し知っておく必要があります。通常、コンピューターは x = s*m*2 eを使用します。ここで、s は符号、m (「仮数」) は (0.5, 1) 内、e (「指数」) は整数です。1/x = s*1/m * 2 -eとなるため、問題は範囲 (0.5, 1) の数値の逆数の計算に縮小され、その範囲では、たとえば 1 を初期推測として使用できます。どうやらその範囲での最適な初期推定は48/17 - 32/17*mです。

すべての数値 s*m*2 eで機能する最初の推測は s*2 -eです。C では、これは次のように計算できます。

double ans = num;
// Initial guess: ans = 2**(-floor(log num))
long int *t = (long int*)(&ans);
*t = (*t & (0x1l<<63)) | (~*t & (0x3FFl << 52)) - (0x1l << 52);
      /* sign */              /* negative exponent */

(注意: エッジの状態は確認していません。)

于 2013-03-13T10:39:19.817 に答える
0

x の逆数を近似するには、乗算と減算のみを使用して、数値 y を推測し、y を 2y − xy^2 で繰り返し置き換えます。y の変化が十分に小さくなる (そしてその状態が続く) と、y は x の逆数の近似値になります。

ans = (2*ans)- (num*ans*ans);

括弧を追加して試してください

構成数学では、実数 x が逆数を持つためには、x ≠ 0 では十分ではありません。代わりに、0 < r < |x| となるような有理数 r を指定する必要があります。前の段落の近似アルゴリズムに関して、これは y の変化が最終的に任意に小さくなることを証明するために必要です。 => この方法では、すべての実数の乗法逆数を差し引くことはできません

すべての非ゼロ元が乗法逆元を持つ環は除算環です。同様に、これが成立する代数は除算代数です。

モジュロを使用しますか? 剰余演算では、a の剰余乗法逆も定義されます。これは、ax ≡ 1 (mod n) となる数値 x です。この乗法逆行列は、a と n が互いに素である場合にのみ存在します。

_編集_ _ ____

最初に ans = num; に注意してください。ans = 2*ans-num*ans*ans; => ans = 2 * ans - 3 * ans = -1 * ans

したがって、常に負の値になります。num に初期化するのは適切ではないと考えてください。ans を 1 に設定してみてください

于 2013-03-13T09:11:43.867 に答える