2016-04-04 10 views
1

二つのベクトル(float値)のドット積を計算するには、異なるマシン上で異なる結果が得られる:フロートのサイズと二重

6.102435302 (Win7 x64, compiler VS12 version 17.00.50727.1) 
6.140244007 (Win7 x64, MinGW, gcc version 5.3.0) 

にコードされています:

#include <iostream> 
#include <iterator> 
#include <fstream> 
#include <vector> 
#include <iomanip> 
#include <algorithm> 

int main(int argc, char** argv){ 

std::ifstream is("test.txt"); 
std::istream_iterator<float> start(is), end; 
std::vector<float> numbers(start, end); 
std::cout << "Read " << numbers.size() << " numbers" << std::endl; 

float product = 0; 
for (int i = 0; i <= numbers.size() - 1; i++) 
    product += (numbers[i])*(numbers[i]); // += means add to product 
std::cout << std::setprecision(10) << product << std::endl; 

std::cin.get(); 
} 

あるtest.txt次のとおりです。

-0.082833 
0.151422 
-0.088526 
-0.538506 
0.646273 
0.266993 
0.200206 
-0.149989 
0.141407 
0.158835 
-0.119255 
-0.039122 
-0.045419 
0.141848 
-0.218912 
-0.264521 
0.032238 
-0.055877 
0.100393 
-0.097075 
-0.006268 
-0.070172 
-0.275793 
0.103654 
-0.075405 
-0.117017 
0.029951 
-0.094158 
-0.168427 
0.381314 
0.144073 
-0.100971 
-0.078645 
0.013768 
0.144876 
0.005855 
-0.018223 
-0.090576 
-0.071564 
-0.029456 
-0.098014 
-0.149181 
0.200667 
-0.189492 
0.264529 
-0.061738 
-0.097826 
0.138872 
-0.241878 
0.019428 
-0.087634 
-0.058300 
-0.009269 
0.039241 
-0.066350 
0.059845 
-0.048516 
-0.070653 
-0.116227 
0.037203 
-0.037091 
-0.097324 
0.043834 
-0.340037 
0.133938 
0.087197 
0.213261 
-0.170708 
-0.151203 
0.052959 
0.027145 
-0.142675 
-0.209020 
0.001813 
-0.022321 
0.190862 
-0.015501 
-0.228589 
-0.038538 
-0.038480 
-0.194482 
0.087518 
-0.257362 
0.160805 
-0.114158 
0.176832 
0.219573 
-0.333160 
-0.068385 
-0.143289 
-0.228401 
0.214679 
0.277186 
-0.130965 
0.142526 
-0.166073 
-0.035309 
0.001260 
-0.064977 
0.020747 
0.014043 
-0.133625 
-0.156975 
-0.043092 
0.154749 
-0.181473 
-0.288339 
-0.144132 
-0.004081 
-0.071694 
-0.094631 
0.483994 
-0.260140 
0.020749 
0.031850 
0.041064 
0.250101 
-0.192338 
-0.222687 
0.114226 
-0.227428 
0.005388 
-0.163509 
-0.135427 
-0.206788 
-0.021093 
0.279840 
-0.055362 
-0.016305 
-0.279524 
0.277402 
0.198076 
0.103796 
-0.272994 
0.306518 
-0.024435 
0.149532 
-0.165079 
-0.394348 
-0.141590 
-0.188541 
0.002890 
0.064264 
-0.045430 
-0.026021 
0.096325 
0.033765 
0.111890 
-0.012204 
0.130457 
-0.106022 
-0.180052 
-0.447620 
0.051825 
0.089245 
-0.265819 
-0.087720 
0.180074 
-0.259521 
-0.356145 
0.162247 
0.282323 
-0.096935 
-0.040101 
-0.214359 
0.357032 
0.195393 
0.150603 
-0.120796 
0.204032 
0.130334 
0.115753 
-0.123727 
-0.107526 
0.196002 
-0.397541 
0.320854 
0.013272 
-0.058865 
0.018108 
0.023616 
-0.053654 
-0.223593 
-0.310052 
0.109229 
-0.107124 
0.074454 
-0.021471 
-0.033081 
0.108072 
-0.067013 
-0.084968 
-0.171947 
0.308421 
-0.204827 
-0.060015 
0.092264 
0.115863 
0.131043 
0.041844 

私は考え、それが何らかの形フロートの大きさと重に依存しており、彼らはこれらのマシンで同じではありません。両方のコンピュータで同じ出力を行うことは可能ですか?

私は(最初の結果6.102435302との)最初のマシンにアクセス全くないが、私は(numpyのと)次のPythonコードと同じ結果を再現することができます。

test = np.loadtxt(test_file, dtype=np.float32) 
result = test.dot(test) 
+2

あなたのコード、入力とコンパイラの設定を投稿できますか? – Micka

+2

あなたの[mcve]はどこですか? –

+2

通常、最後の数ビットの浮動小数点精度は、デフォルトではさまざまなコンパイラ最適化設定で保証されませんが、あなたの値は非常に離れていますが、これは問題ではないと私は考えることができます。あなたのコードを投稿してください。 –

答えて

3

差が大きすぎますdoubleの代わりにfloatを使って説明することができます。コード内の実際のバグを探します。または、あなたの計算が非常に不安定である場合、何が起こっているのかを理解するまで、実際に何が起こっているのかを調べる必要があります。

両方のコンパイラで同じ出力を得るのは簡単です。結果をゼロに設定するだけです。しかし、あなたが望むのはが正しいの結果を得ることです。あなたはひどく間違っている結果があり、信頼できない結果があり、どちらがどちらであるかわからない。結果を同じにすることは、これをカバーするだけで問題を解決することはできません。

+1

ほとんどの場合、これは大きさが非常に近いが極性が反対の大きな積項の結果である可能性が高い。組み合わせると、相対誤差が増加します。これはしばしば病気の状態の行列でも見られます。 – doug

+1

@doug:用語はすべて二乗されているので、すべて正です。 –

+1

ああ、コードとデータを含めてくれてありがとう。これはかなり一般的です。アキュムレータに番号の長いリストを追加すると、アキュムレータの方がはるかに大きくなるため、最初のデータが最後のデータよりも正確に追加されます。 1.333333と.0000333333を追加すると思います。データが読み込まれ、正確な機械精度に丸められずに切り捨てられた場合、より速く積算するバイアスを得ることができます。浮動小数点のベクトルに演算を累積するときは、常にdoubleを使用します。 – doug

3

VS12がループをベクトル化して自動で結果を誤って入力したようです。

あなたが実行している場合は、ループがようにベクトル化:

float product = 0; 
for (int i = 0; i < numbers.size(); i+= 4) 
{ 
    __m128 val = *(__m128*)(&numbers[i]); 
    auto res = _mm_dp_ps (val, val, 255); 
    float result; 
    _mm_store_ss(&result, res); 

    product += result; 
} 

を次にあなたが出結果は次のとおりです。

6.14024353

これは6.102435302のあなたの最初の結果と同じであるが、それは見えますあなたが転記している間に4を逃したように。

少なくとも私が思いつくべき最も良い説明。すでにこの質問で長く過ごしたことがあります:-)

+0

説得力のある仮説に導く非常に素晴らしい探偵作品! –