浮動小数を文字列として受け取り、整数型に変換する実装(個人的なメモ)
これは何
最近コンテストで、入力値が小数第4位程度まで与えられ、その入力値を素直にdouble
で受け取って計算すると丸め誤差で WA となるような問題が散見されるようになった。
(直近の問題だと ABC 191 D Circle Lattice Points がそう)
この手の問題の対策はいくつかあると思う。
- 多倍長浮動小数型がある言語ならそれを使う
long double
等、long
より精度の高い型 + EPSを使う- 入力値を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); } } } }