1

ダブルスでかなり奇妙な問題に遭遇しました。降順でソートされた浮動小数点数(double)のリストがあります。しかし、私のプログラムの後半で、それらが正確にソートされていないことに気付きました。例えば:

0.65801139819
0.6545651031    <-- a
0.65456513001   <-- b
0.64422968678

真ん中の2つの数字が反転しています。この問題は数字の表現にあると思われるかもしれませんが、それらは単に間違って印刷されています。ただし、並べ替えに使用したのと同じ演算子を使用して、各数値を前の数値と比較します。基数10などへの変換は行われません。

double last_pt = 0;
for (int i = 0; i < npoints; i++) {
  if (last_pt && last_pt < track[i]->Pt()) {
    cout << "ERROR: new value " << track[i]->Pt()
         << " is higher than previous value " << last_pt << endl;
  }
  last_pt = track[i]->Pt();
}

値は並べ替え中に比較されます

bool moreThan(const Track& a, const Track& b) {
  return a.Pt() > b.Pt();
}

そして、それらが常に2倍になり、floatに変換されないようにしました。Pt()ダブルを返します。リストにはNaNがなく、ソート後にリストに触れません。

なぜこれなのか、これらの番号の何が問題なのか、そして(どのように)番号を並べ替えて並べ替えたままにすることができますか?

4

2 に答える 2

7

あなたはいつかに変換doubleしていないことを確信していますfloatか? これら 2 つの数値の 2 進数表現を見てみましょう。

0 01111111110 0100111100100011001010000011110111010101101100010101
0 01111111110 0100111100100011001010010010010011111101011010001001

doubleは符号 1 ビット、指数 11 ビット、仮数 53 ビットがあり、 にfloatは符号 1 ビット、指数 8 ビット、仮数 23 ビットがあります。両方の数値の仮数が最初の 23 ビットで同じであることに注意してください。

丸め方法によって、動作が異なります。23 を超えるビットがトリミングされた場合、これら 2 つの数値floatは同じになります。

0 011111110 01001111001000110010100 (trim: 00011110111010101101100010101)
0 011111110 01001111001000110010100 (trim: 10010010011111101011010001001)
于 2012-07-04T14:13:40.243 に答える
1

関数の戻り値を比較しています。浮動小数点の戻り値は、倍精度よりも高い精度を持つ浮動小数点レジスタで返されます。このような 2 つの値 (例: ) を比較する場合a.Pt() > b.Pt()、コンパイラは関数の 1 つを呼び出し、戻り値を型の名前のない一時的な型に格納しdouble(したがって、結果を に丸めますdouble)、他の関数を呼び出して、その結果を比較します (まだ浮動小数点レジスタであり double、格納された値で ) に丸められません。a.Pt() > b.Pt()これは、とb.Pt() > a.Pt()、または の場合になる可能性があることを意味しますa.Pt() > a.Pt()sortこれにより、少し以上の混乱が生じます。(正式には、ここで話してstd::sortいると、これにより未定義の動作が発生し、コア ダンプが発生するケースについて聞いたことがあります。)

一方、Pt()「ダブルフィールドを返すだけ」と言っています。Pt()何も計算しない場合は、これまでに; それが唯一の場合:

double Pt() const { return someDouble; }

の場合、これは問題になりません ( someDoubletype が指定されている 場合double)。拡張精度は、可能なすべての double 値を正確に表すことができます。

于 2012-07-04T14:49:46.867 に答える