(修正)float型とdouble型を比較した場合、常にfloatが速いと思ってはダメらしい
すみません、以前のプログラムにポカがありました
以前、以下のエントリーを書きました。
float型とdouble型を比較した場合、常にfloatが速いと思ってはダメらしい - 強火で進め
http://d.hatena.ne.jp/nakamura001/20090226/1235641233
そして今回、この速度差がどこから来てるのかアセンブリレベルで検証しようと色々と前回のプログラムを見直していたところ大ポカをやらかしている事に気がつきました。
具体的には以下の様な部分です。
NSLog(@"double : time=%f\tval=%f", elapsedTime, floatTotal);
こちら double での計算結果なので本来でればここで指定するのは floatTotal ではなく doubleTotal です。
このようなポカをやらかしたせいで doubleTotal が実際に使用される部分が無いために
コンパイラによる最適化や削除が入らない様なプログラムとなる様に気をつける
という指標を掲げていたにもかかわらずコンパイラによる削除が入ってしまい、それが前回の様な10倍もの速度差に繋がった様です。
前回のエントリーを見てプログラムの修正などされた方がおられましたらご迷惑をおかけしましてすみません。
修正した検証プログラム
修正した検証プログラムは以下となります。前回と同様にボタンなどのActionとして設定し、呼び出して下さい。
#define TEST_NUM 300 #define LOOP_NUM 100000 float floatVal[LOOP_NUM]; double doubleVal[LOOP_NUM]; - (IBAction)run:(id)sender { int i, j; double startTime; double elapsedTime; double doubleTmp; float floatTotal; float floatTmp; double doubleTotal; srand((unsigned)CFAbsoluteTimeGetCurrent()); for (i=0; i<LOOP_NUM; i++) { doubleVal[i] = (double)(rand() % 100) / 100.0; floatVal[i] = (float)doubleVal[i]; } // float型の場合の速度を計測 startTime = CFAbsoluteTimeGetCurrent(); floatTotal = 0.0f; for (i=0; i<TEST_NUM; i++) { for (j=0; j<LOOP_NUM; j++) { floatTotal += floatVal[j] - 0.8f*i/TEST_NUM; } floatTotal *= 0.1f; } elapsedTime = CFAbsoluteTimeGetCurrent() - startTime; NSLog(@"float : time=%f\tval=%f", elapsedTime, floatTotal); startTime = CFAbsoluteTimeGetCurrent(); floatTotal = 0.0f; for (i=0; i<TEST_NUM; i++) { for (j=0; j<LOOP_NUM; j++) { floatTotal += floatVal[j] - 0.8f*(float)i/TEST_NUM; } floatTotal *= 0.1f; } elapsedTime = CFAbsoluteTimeGetCurrent() - startTime; NSLog(@"float(変数をキャスト) : time=%f\tval=%f", elapsedTime, floatTotal); startTime = CFAbsoluteTimeGetCurrent(); floatTotal = 0.0f; for (i=0; i<TEST_NUM; i++) { for (j=0; j<LOOP_NUM; j++) { floatTotal += floatVal[j] - 0.8f*i/(float)TEST_NUM; } floatTotal *= 0.1f; } elapsedTime = CFAbsoluteTimeGetCurrent() - startTime; NSLog(@"float(定数をキャスト) : time=%f\tval=%f", elapsedTime, floatTotal); startTime = CFAbsoluteTimeGetCurrent(); floatTotal = 0.0f; for (i=0; i<TEST_NUM; i++) { for (j=0; j<LOOP_NUM; j++) { floatTotal += floatVal[j] - 0.8f*(float)i/(float)TEST_NUM; } floatTotal *= 0.1f; } elapsedTime = CFAbsoluteTimeGetCurrent() - startTime; NSLog(@"float(両方をキャスト) : time=%f\tval=%f", elapsedTime, floatTotal); startTime = CFAbsoluteTimeGetCurrent(); floatTotal = 0.0f; for (i=0; i<TEST_NUM; i++) { for (j=0; j<LOOP_NUM; j++) { doubleTmp = floatVal[j] - 0.8*i/TEST_NUM; floatTotal += (float)doubleTmp; } floatTotal *= 0.1f; } elapsedTime = CFAbsoluteTimeGetCurrent() - startTime; NSLog(@"float(異なる型のデータを使ったとき) : time=%f\tval=%f", elapsedTime, floatTotal); // double型の場合の速度を計測 startTime = CFAbsoluteTimeGetCurrent(); doubleTotal = 0.0f; for (i=0; i<TEST_NUM; i++) { for (j=0; j<LOOP_NUM; j++) { doubleTotal += doubleVal[j] - 0.8*i/TEST_NUM; } doubleTotal *= 0.1; } elapsedTime = CFAbsoluteTimeGetCurrent() - startTime; NSLog(@"double : time=%f\tval=%f", elapsedTime, doubleTotal); startTime = CFAbsoluteTimeGetCurrent(); doubleTotal = 0.0f; for (i=0; i<TEST_NUM; i++) { for (j=0; j<LOOP_NUM; j++) { doubleTotal += doubleVal[j] - 0.8*(double)i/TEST_NUM; } doubleTotal *= 0.1; } elapsedTime = CFAbsoluteTimeGetCurrent() - startTime; NSLog(@"double(変数をキャスト) : time=%f\tval=%f", elapsedTime, doubleTotal); startTime = CFAbsoluteTimeGetCurrent(); doubleTotal = 0.0f; for (i=0; i<TEST_NUM; i++) { for (j=0; j<LOOP_NUM; j++) { doubleTotal += doubleVal[j] - 0.8*i/(double)TEST_NUM; } doubleTotal *= 0.1; } elapsedTime = CFAbsoluteTimeGetCurrent() - startTime; NSLog(@"double(定数をキャスト) : time=%f\tval=%f", elapsedTime, doubleTotal); startTime = CFAbsoluteTimeGetCurrent(); doubleTotal = 0.0f; for (i=0; i<TEST_NUM; i++) { for (j=0; j<LOOP_NUM; j++) { doubleTotal += doubleVal[j] - 0.8*(double)i/(double)TEST_NUM; } doubleTotal *= 0.1; } elapsedTime = CFAbsoluteTimeGetCurrent() - startTime; NSLog(@"double(両方をキャスト) : time=%f\tval=%f", elapsedTime, doubleTotal); startTime = CFAbsoluteTimeGetCurrent(); doubleTotal = 0.0f; for (i=0; i<TEST_NUM; i++) { for (j=0; j<LOOP_NUM; j++) { floatTmp = doubleVal[j] - 0.8f*i/TEST_NUM; doubleTotal += floatTmp; } doubleTotal *= 0.1; } elapsedTime = CFAbsoluteTimeGetCurrent() - startTime; NSLog(@"double(異なる型のデータを使ったとき) : time=%f\tval=%f", elapsedTime, doubleTotal); }
速度比較
速度比較した結果は以下の様になりました。 float の方が速くなりましたorz
Compile for Thumbにチェック有り(Thumb)
処理時間 | 計算結果 | |
---|---|---|
float | 6.067997 | -3349.595703 |
float(変数をキャスト) | 6.026205 | -3349.595703 |
float(定数をキャスト) | 6.005627 | -3349.595703 |
float(両方をキャスト) | 6.079855 | -3349.595703 |
float(異なる型のデータを使ったとき) | 11.498240 | -3349.595703 |
double | 6.399619 | -3349.497078 |
double(変数をキャスト) | 6.409551 | -3349.497078 |
double(定数をキャスト) | 6.396411 | -3349.497078 |
double(両方をキャスト) | 6.393770 | -3349.497078 |
double(異なる型のデータを使ったとき) | 11.677976 | -3349.496793 |
Compile for Thumbにチェック無し(ARM)
処理時間 | 計算結果 | |
---|---|---|
float | 1.656111 | -3349.364990 |
float(変数をキャスト) | 1.734671 | -3349.364990 |
float(定数をキャスト) | 1.690053 | -3349.364990 |
float(両方をキャスト) | 1.689119 | -3349.364990 |
float(異なる型のデータを使ったとき) | 2.878375 | -3349.364990 |
double | 3.282322 | -3349.269300 |
double(変数をキャスト) | 3.284180 | -3349.269300 |
double(定数をキャスト) | 3.732849 | -3349.269300 |
double(両方をキャスト) | 3.303846 | -3349.269300 |
double(異なる型のデータを使ったとき) | 4.520657 | -3349.269015 |
結果の検証
- float と double の速度比較はiPhoneでは float に軍配が上がる
- 「Compile for Thumbにチェック無し(ARM)」の方が速い
まとめ
float型とdouble型を比較した場合、常にfloatが速いと思ってはダメらしいがiPhoneについては float を使った方が速い。