デルタによって、その対応する長いから逸脱最初の二重は何ですか?

StackOverflow https://stackoverflow.com/questions/732612

  •  06-09-2019
  •  | 
  •  

質問

私はいくつかのデルタによって「同じ値」の長いだけずれ0D上向きから最初の二重を知りたい、1E-8を言います。でも、私はここで失敗しています。私は通常、念のために、マネージ言語を使用するが、Cでこれをやろうとしています。助けてくださいます。


#include <stdio.h>
#include <limits.h>
#define DELTA 1e-8

int main() {
    double d = 0; // checked, the literal is fine
    long i;
    for (i = 0L; i < LONG_MAX; i++) {
         d=i; // gcc does the cast right, i checked
         if (d-i > DELTA || d-i < -DELTA) {
              printf("%f", d);
              break;
         }
    }
}
私は、文字列を比較する上で楽しいCのキャスティングを好む -

私は、問題はそのディは私を倍増し、したがって、D ==ためにキャストして、違いは、私はこれを適切に検出することができます他にどのように常に0であることを推測しています、永遠に取ることになる。

のANSWER の:私たちは期待とまったく同じです。 2 ^ 53 + 1 = 9007199254740993、標準C / UNIX / POSIXツールに応じて差の最初のポイントです。彼のプログラムのために多くのPAXに感謝します。そして、私は数学が再び勝利思います。

役に立ちましたか?

解決

IEE754でダブルスは、それらがまで正確に番号を格納できることを意味52ビットの精度を有する(少なくとも)2 51

あなたのlong型が32ビットであれば、彼らは唯一の(正)の範囲になります。

0〜2 31 正確doubleとして表現できないことは、32ビット長はありませんので。 64ビット長のために、それは(約)2 52 私はないゼロで、周りが開始されると思います。

であろう

あなたは、障害が発生し始める場所を検出するために、以下のプログラムを使用することができます。以前のバージョンでは、私は継続的に倍増番号の最後の桁が列{2,4,8,6}を次の事実に頼っていました。しかし、私は全体の数だけでなく、最後の数字をチェックするために、既知の信頼できるツール(bc)を使用することを最終的に選んだ。

(私は<それは2までの特定の番号で支障がなかったので、とても個人的には思いません。こののかもしれないのは、むしろダブルスの実際の精度よりもsprintf()の行動によって影響されることに注意してくださいSUP> 143 )。

このプログラムは、次のとおりです。

#include <stdio.h>
#include <string.h>

int main() {
    FILE *fin;
    double d = 1.0; // 2^n-1 to avoid exact powers of 2.
    int i = 1;
    char ds[1000];
    char tst[1000];

    // Loop forever, rely on break to finish.
    while (1) {
        // Get C version of the double.
        sprintf (ds, "%.0f", d);

        // Get bc version of the double.
        sprintf (tst, "echo '2^%d - 1' | bc >tmpfile", i);
        system(tst);
        fin = fopen ("tmpfile", "r");
        fgets (tst, sizeof (tst), fin);
        fclose (fin);
        tst[strlen (tst) - 1] = '\0';

        // Check them.
        if (strcmp (ds, tst) != 0) {
            printf( "2^%d - 1 <-- bc failure\n", i);
            printf( "   got       [%s]\n", ds);
            printf( "   expected  [%s]\n", tst);
            break;
        }

        // Output for status then move to next.
        printf( "2^%d - 1 = %s\n", i, ds);
        d = (d + 1) * 2 - 1;  // Again, 2^n - 1.
        i++;
    }
}

これは、までいっています

2^51 - 1 = 2251799813685247
2^52 - 1 = 4503599627370495
2^53 - 1 = 9007199254740991
2^54 - 1 <-- bc failure
   got       [18014398509481984]
   expected  [18014398509481983]

私は失敗することを期待される場所についてです。

はさておき、私はもともとフォーム2 の番号を使用されるn それは私に起きたとおります:

2^136 = 87112285931760246646623899502532662132736
2^137 = 174224571863520493293247799005065324265472
2^138 = 348449143727040986586495598010130648530944
2^139 = 696898287454081973172991196020261297061888
2^140 = 1393796574908163946345982392040522594123776
2^141 = 2787593149816327892691964784081045188247552
2^142 = 5575186299632655785383929568162090376495104
2^143 <-- bc failure
   got       [11150372599265311570767859136324180752990210]
   expected  [11150372599265311570767859136324180752990208]

sizeofでチェック)二重である8バイトのサイズを有します。これは、これらの数字ははるかに長いダブルスとのために表現することができるバイナリ形式の"1000..."であったが判明しました。私が使用してに切り替えたときです2 N -1より良いビットパターン取得する:すべての1ビットを

他のヒント

doubleにキャストしたときに「間違っている」であると最初に長いが1E-8でオフではありません、それは限り、二重がその仮の長いを収めることができ、それはそれを正確に表現すると1がオフになりますます。

私は二重のオフセット対精度のために持っているが、それはあなたにそれを表現することができ、最大サイズを言うだろう正確にどのように多くのビットを忘れてしまいました。あなたは1と左シフトで開始することによって、より迅速にそれを見つけることができますので、間違っていることが第一の長は、バイナリ形式万を...、持っている必要があります。

ウィキペディアは異なる値にキャストする第一長が2 ^ 53であることを意味すべきである暗黙の開始1をカウントしない、仮に52ビットを言う。

私はこの議論でのFortran 95と後継者を言及することを躊躇していますが、

、私は、Fortran 1990年の標準的なので、表現のREALとの差が所定REALについて何であるかがわかりますSPACING本来の機能を提供してきましたことを言及します。あなたは(X)> DELTAの間隔時に停止し、この上のバイナリ検索を行うことができます。あなたは(IEEE754標準である可能性が高い)に興味があるのと同じ浮動小数点モデルを使用するコンパイラのために、あなたは同じ結果を得る必要があります。

は手オフ、私はダブルスは正確に(その範囲内で)すべての整数を表すことができると考えています。

が一致しない場合は、その後、あなたはそれらのいずれよりも精度のものにIとDの両方をキャストしたいとしています。おそらく、長い二は動作します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top