[C] Cで10進小数を使う方法

2016年6月6日月曜日

C

CでJavaのBigDecimalのような10進小数を扱えるライブラリはないかなと探していたのですが、decNumberというのがありました。

The decNumber Library
http://speleotrove.com/decimal/decnumber.html

gccにも使われているようで、なかなかよさそう。
共有ライブラリ形式ではなく、ソースコード諸共コンパイルするタイプだけど、取得元によってライセンスが変わってくるので、注意が必要。

http://download.icu-project.org/files/decNumber/
こちらはICUライセンスになる。
#ICUライセンスはライセンステキストを添付すれば、再頒布可能。

https://github.com/gcc-mirror/gcc/tree/master/libdecnumber
gccリポジトリから取得した場合はGPLになる。

基本となるのはdecNumberという型だけど、10進数の浮動小数点数なので、内部表現は以下となる。

decNumber = (-1)符号 × 仮数 × 10指数

このうち、仮数部の桁数と指数部の上限、下限を指定して、数値の範囲を決めることができる。
また、DECNUMDIGITSマクロはデフォルトで割り当てられる桁数をコンパイル時に決定するもので、アプリケーション全体で使用するバッファサイズと速度の兼ね合いで決めればいいと思う。

小数点第2位まで、計算して四捨五入で計算して最後に整数に丸めるのはこんな感じ。
#define DECNUMDIGITS 10

#include 
#include "decNumber/decNumber.h"

int main(void) {
    decContext context;
    decContextDefault(&context, DEC_INIT_BASE);
    decContextSetRounding(&context, DEC_ROUND_HALF_UP);
    context.digits = 10;
    context.emax = 2;
    context.emin = -2;

    // decNumber = (-1)sign * coefficient * 10^exponent
    decNumber a, b, tax, place;
    decNumberFromString(&a, "134.00", &context);
    decNumberFromString(&b, "82.00", &context);
    decNumberFromString(&tax, "0.08", &context);
    decNumberFromString(&place, "0", &context);

    // a = a + b
    decNumberAdd(&a, &a, &b, &context);
    decNumberMultiply(&a, &a, &tax, &context);

    char str[32];
    decNumberToString(&a, str);
    printf("%s\n", str);

    decNumberRescale(&a, &a, &place, &context);
    decNumberToString(&a, str);
    printf("%s\n", str);

    return 0;
}
上記のようにサイズをすべてプログラマーが指定するのではなく、decSingle, decDouble, decQuadを使うことによって、あらかじめ決められたサイズの変数を使うこともできる。
# こちらの方がパフォーマンスもいいみたい。