C言語における割り算の、小数点以下を四捨五入する場合について記載します。
小数点以下を切り上げする場合については 整数の割り算で小数点を切り上げる を参照ください。


 

整数の四捨五入

 C言語で割り算の四捨五入を行いたい場合は以下のように書くことができます。
 この例は math.hdouble を使う非常にリッチな方法です。

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
    #include <math.h>
‌ 
    double  myWaruKazu      = 5u;   // 割る数 
    double  myWarareruKazu  = 6u;   // 割られる数 
    unsigned int myResult;          // 結果 
‌ 
    double  myWork;
    double  myLower;
‌ 
    // ====== 普通に小数点以下の切り捨て割り算する
    myResult    = (unsigned int) (myWarareruKazu / myWaruKazu);
‌ 
    // ====== 割り算結果の小数点以下を取得する
    myLower = modf( myWarareruKazu / myWaruKazu, &myWork );
‌ 
    // ====== 小数点以下が0.5以上なら1足す(四捨五入)
    if0.5 <= myLower ){
        myResult++;
    }
‌ 
‌ 
このコードは CodePublisher で生成しています

[2012.01.15] 上記の式が正しいことを、100000*100000回の試験にて確認しました

 

パフォーマンスを上げた式

 上の式は非常にリッチな書き方でしたので、次の例では math.hdouble も使わず書いてみます。

1.
2.
3.
4.
5.
6.
7.
8.
9.
    unsigned int myWaruKazu      = 5u;   // 割る数 
    unsigned int myWarareruKazu  = 6u;   // 割られる数 
    unsigned int myResult;               // 結果 
‌ 
    // ====== 最初に10倍しておいて普通に割り算する
    myResult    = (myWarareruKazu * 10u/ myWaruKazu;
‌ 
    // ====== 四捨五入の0.5を10倍して足し、最初の10倍を元に戻す
    myResult    = (myResult + 5u/ 10u;
このコードは CodePublisher で生成しています

[2012.01.15] 上記の式が正しいことを、100000*100000回の試験にて確認しました

 

パフォーマンスを上げ、扱える範囲を大きくした式

 上の式でパフォーマンスが上がりましたが、割られる数を10倍してしまっています。
 これによって割られる数として扱える範囲が1/10まで減少してしまいました。
 この点を改善して割る数として扱える範囲が1/2まで減少するだけで済む式にしてみました。

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
‌ 
    unsigned int myWaruKazu      = 5u;   // 割る数 
    unsigned int myWarareruKazu  = 6u;   // 割られる数 
    unsigned int myResult;               // 結果 
‌ 
    // ====== 普通に小数点以下切り捨て割り算する
    myResult    = myWarareruKazu / myWaruKazu;
‌ 
    // ====== もし余りの2倍が割る数より大きいなら、四捨五入で切り上げされるべき
    if( myWaruKazu <= ( (myWarareruKazu % myWaruKazu) * 2u) ){
        myResult++//  四捨五入による切り上げ
    }
‌ 
このコードは CodePublisher で生成しています

[2012.01.15] 上記の式が正しいことを、100000*100000回の試験にて確認しました

 

ついでにマクロにしよう

 上記の式を #define で仮引数付きマクロ _DIVRND() にしてみました。
 _UNSAFE_DIVRNDはゼロ割に対応していません。(vWaruがゼロだとヤバい)

1.
2.
3.
4.
5.
#define _DIVRND( vWarareru, vWaru )      ( !(vWaru) ? 0 : _UNSAFE_DIVRND( vWarareru, vWaru ) )
#define _UNSAFE_DIVRND( vWarareru, vWaru ) ( ( ( (vWarareru) % (vWaru) ) *2 ) >= (vWaru) ?  
                                            ( ( (vWarareru) / (vWaru) ) + 1u) :              
                                            ( ( (vWarareru) / (vWaru) ) ) )
‌ 
このコードは CodePublisher で生成しています

[2012.01.15] 上記の式が正しいことを、100000*100000回の試験にて確認しました

コメント

  • コメントはまだありません。

コメントを投稿する

コメントを投稿する場合は以下に注意してください。

・記事に関係する内容であること
・特別な理由がない限り「全体公開」であること

これさえ守っていただければどんな内容でも投稿可能です。
皆様の質問やコメントは他の方の問題解決に繋がりますのでご協力ください。

コメント投稿フォーム
名前
メール
URL
コメント
閲覧制限

コメントを投稿するには、以下の問題に答えてください。
問題:「このサイト名をカタカナ六文字にして入力してください」