

AtCoderの[Panasonic
2020のコンテストのC問題](https://atcoder.jp/contests/panasonic2020/tasks/panasonic2020_c)について質問します.  
ACしたコードは以下になります。

[code]

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> P;
    
    //マクロ
    #define REP(i,n) for(ll i=0;i<(ll)(n);i++)
    #define REPD(i,n) for(ll i=(ll)(n)-1;i>=0;i--)
    #define FOR(i,a,b) for(ll i=(a);i<=(b);i++)
    #define FORD(i,a,b) for(ll i=(a);i>=(b);i--)
    #define ALL(x) (x).begin(),(x).end() //sortなどの引数を省略したい
    #define SIZE(x) ((ll)(x).size()) //sizeをsize_tからllに直しておく
    #define MAX(x) *max_element(ALL(x))
    #define INF 1000000000000 //10^12
    #define MOD 10000007 //10^9+7
    #define PB push_back
    #define MP make_pair
    #define F first
    #define S second
    
    int main(int argc, char const *argv[]) {
    
      ll a, b, c; cin >> a >> b >> c;
      ll right = 4 * a * b, left, tmp = c - a - b;
      left = pow(tmp,2);
      /* cout << right << " " << left << endl; */
      if (4 * a * b < tmp * tmp && tmp > 0) cout << "Yes" << endl;
      else cout << "No" << endl;
      return 0;
    }
    
[/code]

次に、原因不明でWAしたコードは以下です。

[code]

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> P;
    
    //マクロ
    #define REP(i,n) for(ll i=0;i<(ll)(n);i++)
    #define REPD(i,n) for(ll i=(ll)(n)-1;i>=0;i--)
    #define FOR(i,a,b) for(ll i=(a);i<=(b);i++)
    #define FORD(i,a,b) for(ll i=(a);i>=(b);i--)
    #define ALL(x) (x).begin(),(x).end() //sortなどの引数を省略したい
    #define SIZE(x) ((ll)(x).size()) //sizeをsize_tからllに直しておく
    #define MAX(x) *max_element(ALL(x))
    #define INF 1000000000000 //10^12
    #define MOD 10000007 //10^9+7
    #define PB push_back
    #define MP make_pair
    #define F first
    #define S second
    
    int main(int argc, char const *argv[]) {
    
      ll a, b, c; cin >> a >> b >> c;
      ll right = 4 * a * b, left, tmp = c - a - b;
      left = pow(tmp,2);
      /* cout << right << " " << left << endl; */
      if (right < left && tmp > 0) cout << "Yes" << endl;
      else cout << "No" << endl;
      return 0;
    }
    
[/code]

こちらでも演算の途中経過を変数に代入するかそのままif文に含めるかの違いしか無いように感じますが、何故かWAしてしまいます。

原因がわかる方はご享受いただけると幸いです。


CC BY-SA 4.0
2020-06-16T18:30:00.917
67737
2020-06-16T21:52:16.407
2020-06-16T21:52:16.407
19110
31609
question
c++
C++ 演算の順により答えが変わってしまう


調べたところ、pow()関数はlong long型を引数として受け付けるオーバーロードはないようです。  
double型などに変換されますので、引数がとても大きい場合（概ね16桁超え）、誤差が発生します。


CC BY-SA 4.0
2020-06-16T18:51:29.673
67738
2020-06-16T18:51:29.673
25396
67737
answer


`std::pow()`は`double`の値を引数にとって戻り値として返します。`long
long`の有効桁数がほぼ19桁あるのに対し、`double`の有効桁数が15桁ちょっとであるため、誤差が生じているのだと思います。

[code]

    #include <cmath>
    #include <iostream>
    
    int main() {
        long long tmp = 123456789;
        long long left = std::pow(tmp, 2);
    
        std::cout << tmp * tmp << '\n';
        std::cout << left << '\n';
    
    }
    
[/code]

を実行すると結果は

[code]

    15241578750190521
    15241578750190520
    
[/code]

となり、最後の一桁が違っているのがわかります。


CC BY-SA 4.0
2020-06-16T18:56:58.043
67739
2020-06-16T18:56:58.043
3605
67737
answer