LoginSignup
10
10

More than 5 years have passed since last update.

C++で、引数の指定によってはsqrt(平方根)の値が異なることがある。

Last updated at Posted at 2015-08-27

初めに

色々実験してる時に遭遇しました。
実際、これで嵌るということはなかなかなさそうですが(僕は有りましたが)、
こういうこともあるということで記事にしました。

当初は
「C++で、定数による最適化でsqrt(平方根)の値が異なることがある」としてましたが、定数による最適化のせいではなかったので改めました。

環境

コンパイラは ideoneのC++14 (gcc 5.1)
で確認してます。

実験

#include <iostream>
#include <cmath>
#include <iomanip>
#include <assert.h>
using namespace std;
int main(){

    long long int calc = sqrt(static_cast<long double>(18014415152484098LL));

    cout << calc <<endl;

    long long int calc2 = sqrt(static_cast<double>(18014415152484098LL));

    cout << calc2 <<endl;

    long long int calc3 = sqrt(static_cast<long long int>(18014415152484098LL));

    cout << calc3 <<endl;

    long long int calc4 = sqrt(18014415152484098LL);

    cout << calc4 <<endl;

    cout<<setprecision(20)<< 18014415152484098LL <<endl;

    cout<<setprecision(20)<< static_cast<double>(18014415152484098LL) <<endl;
    cout<<setprecision(20)<< static_cast<long double>(18014415152484098LL) <<endl;


    return 0;
}

これを実行すると、

134217789
134217790
134217790
134217790
18014415152484098
18014415152484096
18014415152484098

と実行される環境があります。

これはsqrt関数でlong doubleに明示的に型指定しないと、doubleになり情報落ちが発生します。

変換後の型 値(整数部)
long long int 18014415152484098
long double 18014415152484098
long double sqrt 134217789
double 18014415152484096
double sqrt 134217790

コンパイル時の最適化

また、sqrtの引数が定数とみなせる場合、コンパイラが最適化を行い、
sqrt(18014415152484098) -> 134217790
という感じにコンパイル時に即値にしているようです。
(型にあったsqrt呼出しのようです。)

アセンブラを吐き出してみる

アセンブラを吐くテクニックを教えてもらったので、
実際のアセンブラを吐き出してみるとこのような感じです。
https://ideone.com/4Zoktm

134217790の16進数表現(0x800003e)を
即値で持ってるのがわかります。
(calc2は2箇所で使われているので,2つあるようです)

future study

以下のコードで最初の出力がなぜ
「134217789になる」のかは、まだ理解できてません。
http://ideone.com/Y4XMOY

まとめ

sqrt関数ややこしい。
C++の定数の最適化すごい!

10
10
15

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
10