2

のような無理数があるとし\sqrt{3}ます。これは無理数なので、10 進表現はありません。したがって、IEEE 754 double で表現しようとすると、エラーが発生します。

桁数の多い 10 進数表現は次のとおりです。

1.7320508075688772935274463415058723669428052538103806280558069794519330169088
  00037081146186757248575675...

今、私が計算する\sqrt{3}と、次のようになります1.732051

#include <stdio.h> // printf
#include <math.h>   // needed for sqrt

int main() {
    double myVar = sqrt (3);
    printf("as double:\t%f\n", myVar);
}

Wolfram|Alphaによると、 のエラーがあり1.11100... × 10^-7ます。

エラーを自分で計算する方法はありますか?

(C++、Python、またはJavaに切り替えてもかまいません。単純な代替手段がなければ、Mathematica を使用することもできます)

明確にするために: sqrt{3} に対してのみ機能するソリューションは必要ありません。任意の数値のエラーを返す関数を取得したいと思います。それが不可能な場合は、少なくとも Wolfram|Alpha がより多くの値を取得する方法を知りたいです。

私の試み

この質問を書いているときに、私はこれを見つけました:

#include <stdio.h> // printf
#include <math.h>  // needed for sqrt
#include <float.h> // needed for higher precision

int main() {
    long double r = sqrtl(3.0L);
    printf("Precision: %d digits; %.*Lg\n",LDBL_DIG,LDBL_DIG,r);
}

これで、 Wolfram|Alpha2.0 * 10^-18に従ってエラーを取得できます。したがって、これはエラーの適切な推定を得るのに十分近いと思いました。私はこれを書きました:

#include <stdio.h> // printf
#include <math.h>  // needed for sqrt
#include <float.h>

int main() {
    double myVar = sqrt (3);
    long double r = sqrtl(3.0L);
    long double error = abs(r-myVar) / r;
    printf("Double:\t\t%f\n", myVar);
    printf("Precision:\t%d digits; %.*Lg\n",LDBL_DIG,LDBL_DIG,r);
    printf("Error:\t\t%.*Lg\n", LDBL_DIG, error);
}

しかし、それは出力します:

Double:     1.732051
Precision:  18 digits; 1.73205080756887729
Error:      0

エラーを取得するにはどうすれば修正できますか?

4

6 に答える 6

2

すべてのプログラマーがゴールドバーグの浮動小数点演算について知っておくべきことは、あなたが探している明確なガイドです。

https://ece.uwaterloo.ca/~dwharder/NumericalAnalysis/02Numerics/Double/paper.pdf

于 2013-03-07T16:35:52.827 に答える
1

printf%f精度なしで使用すると、2倍の6桁に丸められます。

例えば

double x = 1.3;
long double y = 1.3L;
long double err = y - (double) x;
printf("Error %.20Lf\n", err);

私の出力:-0.00000000000000004445

結果が0の場合、long doubledoubleは同じです。

于 2013-03-07T16:26:56.173 に答える
0

Double: 1.732051ここでの印刷に間違いがありますprintf("Double:\t\t%f\n", myVar);

doublemyVarの実際の値は

1.732050807568877281 //18 digits

したがって、1.732050807568877281-1.732050807568877281はゼロです

于 2013-03-07T16:24:18.397 に答える
0

計算の実際の値を含むことが保証されている区間を取得する 1 つの方法は、区間演算を使用することです。次に、結果を区間と比較すると、最悪の場合、計算が実際の計算からdoubleどれだけ離れているかがわかります。double

Frama-C の価値分析は、オプションでこれを行うことができます-all-rounding-modes

double Frama_C_sqrt(double x);

double sqrt(double x)
{
  return Frama_C_sqrt(x);
}

double y;

int main(){
  y = sqrt(3.0);
}

以下を使用してプログラムを分析します。

frama-c -val t.c -float-normal -all-rounding-modes
[value] Values at end of function main:
      y ∈ [1.7320508075688772 .. 1.7320508075688774]

これは、 の実際の値sqrt(3)、したがって、yプログラムが実数で計算された場合に variable に含まれる値が、double境界内にあることを意味します[1.7320508075688772 .. 1.7320508075688774]

Frama-C の値分析は型をサポートしていませんlong doubleが、私の理解が正しければ、long doubleで作成されたエラーを推定するための参照としてのみ使用していましたdouble。この方法の欠点は、long doubleそれ自体が不正確であることです。Frama-C の値分析に実装されている区間演算により、計算の実際の値が表示された境界内にあることが保証されます。

于 2013-03-10T09:46:35.603 に答える
0

C 標準によると、printf("%f", d)デフォルトでは小数点以下 6 桁になります。これは double の完全な精度ではありません。

double と long double がたまたまアーキテクチャ上で同じである可能性があります。私のアーキテクチャではサイズが異なり、サンプルコードでゼロ以外のエラーが発生します。

于 2013-03-07T16:30:38.863 に答える