Arc's blog

競プロなど

C++で浮動小数点型を扱うときのメモ(精度比較,精度設定)

(Qiitaを退会したため,同名の記事をQiitaからはてなに移行しました) AtCoderで問題を解いていたら、浮動小数点関連のC++の仕様でつまずいたのでメモ。

精度比較してみる

サンプルコード

#include<iostream>
#include<cstdio>
#include<iomanip>
using std::cout;
using std::cin;
using std::endl;

int main(void){
    double pi=3.1415926535898;
    double kilopi=3141.5926525898;

    cout<<"pi---------------"<<endl;
    cout<<"cout "<<pi<<endl;
    cout<<"cout (set(10))"<<std::setprecision(10)<<pi<<endl;
    cout<<"cout (fixed,set(10))"<<std::fixed<<pi<<endl;
    printf("printf %f\n",pi);
    printf("printf (%%.10f) %.10f\n",pi);

    cout<<std::defaultfloat<<std::setprecision(6);
    cout<<endl;

    cout<<"kilopi---------------"<<endl;
    cout<<"cout "<<kilopi<<endl;
    cout<<"cout (set(10))"<<std::setprecision(10)<<kilopi<<endl;
    cout<<"cout (fixed,set(10))"<<std::fixed<<kilopi<<endl;
    printf("printf %f\n",kilopi);
    printf("printf (%%.10f) %.10f\n",kilopi);
    
    return 0;
}

出力

pi---------------
cout 3.14159
cout (set(10))3.141592654
cout (fixed,set(10))3.1415926536
printf 3.141593
printf (%.10f) 3.1415926536

kilopi---------------
cout 3141.59
cout (set(10))3141.592653
cout (fixed,set(10))3141.5926525898
printf 3141.592653
printf (%.10f) 3141.5926525898

分かること

  • coutはデフォルトで 「整数部、小数部合わせて6桁
  • printfはデフォルトで 「小数部6桁
  • マニピュレータstd::setprecision(n)を使うことで「整数部、小数部合わせてn桁」にできる
  • マニピュレータstd::fixedを使うことで「小数部n桁」にできる(小数部がn桁未満だった場合、0で埋められるみたい)
  • マニピュレータstd::defaultfloatを使うことでリセットできる(std::setprecision()で指定したものはリセットされないみたい。要手動リセット)
  • マニピュレータを使う際は#include<iomanip>が必要

簡単なバグ回避策

一番最初にstd::cout<<std::fixed<<std::setprecision(10)としておけば、浮動小数点型を出力する時に全て小数部10桁にできる、との情報をTwitterで教えてもらった。競技プログラミングをする限りではこれで全く問題ない。

参考資料

MaryCore 【C++】小数点の桁数を指定する方法と注意点【cout/iostream】 蒼色工房 printf出力書式まとめ