6

パラメータとして 4 つの double を取り、この指定されたパラメータを使用して次の方法で計算された別の double を返す関数 getSlope があります。

double QSweep::getSlope(double a, double b, double c, double d){
double slope;
slope=(d-b)/(c-a);
return slope;
}

問題は、たとえば次のように引数を指定してこの関数を呼び出す場合です。

getSlope(2.71156, -1.64161, 2.70413, -1.72219);

返される結果は次のとおりです。

10.8557

これは私の計算では良い結果ではありません。Mathematica を使用して勾配を計算しましたが、同じパラメータの勾配の結果は次のとおりです。

10.8452

または精度のために桁数を増やします:

10.845222072678331.

プログラムから返された結果は、その後の計算では適切ではありません。さらに、プログラムが 10.845222072678331 から始まる 10.8557 を返す方法がわかりません (これが除算のおおよその結果であると仮定して)。自分の部門で良い結果を得るにはどうすればよいですか?

前もってありがとう、マダリナ


コマンドラインを使用して結果を出力します。

std::cout<<slope<<endl;

別のプログラム(グラフを計算するプログラム)からパラメーターを読み取ったため、パラメーターが適切ではない可能性があります。グラフからこのパラメーターを読み取った後、値を確認するために表示しましたが、表示されたベクトルは同じではない可能性があります計算値の内部精度..私はそれが本当に奇妙であることを知りません.いくつかの数値エラーが表示されます..)

パラメータを読み取っているグラフが計算されるとき、C++ で記述された数値ライブラリ (テンプレート付き) が使用されます。この計算には OpenGL は使用されません。

ありがとう、マダリナ

4

8 に答える 8

7

double の代わりに float を試してみたところ、結果として 10.845110 が得られました。それはまだマダリナの結果よりも良く見えます.

編集:

なぜこのような結果が得られたのかがわかると思います。a、b、c、および d パラメーターを別の場所から取得して印刷すると、丸められた値が得られます。それを Mathemtacia (または calc ;) ) に入れると、異なる結果が得られます。

パラメータの 1 つを少し変更してみました。私がしたとき:

double c = 2.7041304;

私は10.845806を取得します。c に 0.0000004 を追加するだけです! したがって、あなたの「エラー」はエラーではないと思います。a、b、c、および d をより高い精度で出力し、それらを Mathematica に入力します。

于 2009-03-30T10:47:41.180 に答える
5

次のコード:

#include <iostream>
using namespace std;

double getSlope(double a, double b, double c, double d){
    double slope;
    slope=(d-b)/(c-a);
    return slope;
}

int main( ) {
    double s = getSlope(2.71156, -1.64161, 2.70413, -1.72219);
    cout << s << endl;
}

g++で10.8452の結果が得られます。結果をコードにどのように出力しますか?

于 2009-03-30T09:40:28.457 に答える
5

プロジェクトで DirectX または OpenGL を使用している可能性はありますか? その場合、倍精度をオフにすることができ、奇妙な結果が得られます。

精度設定を確認するには、

std::sqrt(x) * std::sqrt(x)

結果は x にかなり近くなければなりません。私はずっと前にこの問題に遭遇し、すべての数式をチェックするのに 1 か月を費やしました。しかし、私は見つけました

D3DCREATE_FPU_PRESERVE
于 2009-03-30T09:34:38.953 に答える
3

ここでの問題は、(ca) が小さいことです。そのため、この例では浮動小数点演算に固有の丸め誤差が拡大されています。一般的な解決策は、小さな数で割らないように方程式を作り直すことですが、ここでどのように行うかはわかりません。

編集:

この質問に対する Neil のコメントは正しいです。VB で Doubles を使用して答えを計算し、mathematica と同じ答えを得ました。

于 2009-03-30T09:36:19.730 に答える
2

得られる結果は、32 ビット演算と一致しています。環境について詳しく知らなければ、何をすべきかをアドバイスすることはできません。

表示されているコードが実行されていると仮定すると、つまり、何も文字列や浮動小数点数に変換していない場合、C++ 内での修正はありません。それはあなたが示したコードの外にあり、環境に依存します。

Patrick McDonald と Treb があなたの入力の精度と のエラーの両方をa-c持ち出したので、それを調べてみようと思いました. 丸め誤差を調べる手法の 1 つは、値が表す上限と下限を明示的にする区間演算です (これらは浮動小数点数では暗黙的であり、表現の精度に固定されます)。各値を上限と下限として扱い、表現の誤差 (double 値 x の場合は約 x * 2 ^ -53) によって境界を拡張することにより、最悪の場合の精度誤差を考慮した値の精度。

たとえば、[1.0, 2.0] の範囲の値から [0.0, 1.0] の範囲の値を減算すると、結果は [下(0.0),上(2.0)] の範囲内にある必要があります。最小結果は 1.0-1.0 で、最大値は 2.0-0.0 です。belowaboveは floor と ceiling と同等ですが、整数ではなく次の表現可能な値を対象としています。

最悪の場合の二重丸めを表す間隔を使用します。

getSlope(
 a = [2.7115599999999995262:2.7115600000000004144], 
 b = [-1.6416099999999997916:-1.6416100000000002357], 
 c = [2.7041299999999997006:2.7041300000000005888], 
 d = [-1.7221899999999998876:-1.7221900000000003317])
(d-b) = [-0.080580000000000526206:-0.080579999999999665783]
(c-a) = [-0.0074300000000007129439:-0.0074299999999989383218]

to double precision [10.845222072677243474:10.845222072679954195]

したがって、はまたはにc-a比べて小さいですが、倍精度丸めと比較すると依然として大きいため、考えられる最悪の倍精度丸めを使用していた場合、その値が 12 桁 (10.8452220727) の精度であると信頼できます。倍精度でいくつかの数字を失いましたが、入力の重要性以上に取り組んでいます。ca

しかし、入力が有効数字の数だけ正確である場合、double 値 2.71156 +/- eps ではなく、入力範囲は [2.711555,2.711565] になるため、次の結果が得られます。

getSlope(
 a = [2.711555:2.711565], 
 b = [-1.641615:-1.641605], 
 c = [2.704125:2.704135], 
 d = [-1.722195:-1.722185])
(d-b) = [-0.08059:-0.08057]
(c-a) = [-0.00744:-0.00742]

to specified accuracy [10.82930108:10.86118598]

これははるかに広い範囲です。

しかし、計算の精度を追跡するためには道を踏み外す必要があり、浮動小数点に固有の丸め誤差はこの例では重要ではありません.最悪の場合の倍精度丸めで12桁まで正確です.

一方、入力が 6 桁しかわからない場合は、10.8557 と 10.8452 のどちらを取得しても実際には問題になりません。どちらも [10.82930108:10.86118598] 内にあります。

于 2009-03-30T12:31:31.993 に答える
1

引数も出力してください。私が推測するように、パラメーターを 10 進表記で転送していると、パラメーターのすべての精度が失われます。問題は、1/5 が 2 進数の無限級数であるため、たとえば 0.2 が .001001001 になることです。また、2 進数の浮動小数点数を 10 進数のテキスト表現に変換するときに、10 進数が切り捨てられます。

それに加えて、コンパイラが精度よりも速度を選択することがあります。これは文書化されたコンパイラ スイッチである必要があります。

于 2009-03-30T10:01:56.627 に答える
0

パトリックは、(ca) が主な原因であることについて正しいようです。

デシベル = -1,72219 - (-1,64161) = -0,08058

約 = 2,70413 - 2,71156 = -0,00743

S = (デシベル)/(ca)= -0,08058 / -0,00743 = 10,845222

6 桁の精度で開始し、減算によって 3 桁と 4 桁に減少します。私の最善の推測は、数値 -0,00743 を double で正確に表すことができないため、追加の精度が失われることです。次のように、精度の高い中間変数を使用してみてください。

double QSweep::getSlope(double a, double b, double c, double d)
{
    double slope;
    long double temp1, temp2;

    temp1 = (d-b);
    temp2 = (c-a);
    slope = temp1/temp2;

    return slope;
}
于 2009-03-30T10:06:36.380 に答える
-1

進行中の学術的な議論は、プログラミング言語の限界について学ぶのに最適ですが、問題に対する最も簡単な解決策は、任意精度演算のデータ構造であることに気付くかもしれません。

これには多少のオーバーヘッドがありますが、かなり保証された精度で何かを見つけることができるはずです。

于 2009-05-27T19:10:22.930 に答える