Baby Stepsなブログ

競プロとか。間違ったこと書いてあったら@pi0nep1oneにご連絡ください。

浮動小数を文字列として受け取り、整数型に変換する実装(個人的なメモ)

これは何

最近コンテストで、入力値が小数第4位程度まで与えられ、その入力値を素直にdoubleで受け取って計算すると丸め誤差で WA となるような問題が散見されるようになった。

(直近の問題だと ABC 191 D Circle Lattice Points がそう)

atcoder.jp

この手の問題の対策はいくつかあると思う。

  1. 多倍長浮動小数型がある言語ならそれを使う
  2. long double等、longより精度の高い型 + EPSを使う
  3. 入力値を10p 倍して整数に変換して計算した後、10p で割って最終的な解を求める

以下の実装は、3における入力値を10pするためのもので、丸め誤差が生じないように文字列として入力値を受け取り、それを long long 型で返すものである。(毎回実装考える時間がもったいないので、実装を残しておく)

実装

/**
 * @param s 文字列化した小数値
 * @param p sの数値を 10^p 乗倍する
 * 
 * 10^p乗倍した結果、小数点以下が0になることと、その値がlong long型に収まる必要がある
 */
long long string_double_to_long(const string & s, const int p){
  if(s.find('.')==string::npos){
    long long p=1;
    while(p--) p*=10;
    return stoll(s)*p;
  }else{
    int n=s.size();
    for(int i=0; i<n; i++){
      if(s[i]=='.'){
        int tail_len=n-i-1;
        int loop_cnt=p-tail_len;
        auto t=s.substr(0,i)+s.substr(i+1,n);
        while(loop_cnt--) t.push_back('0');
        return stoll(t);
      }
    }
  }
}