"abacus": Abacus utility in C
hacker emblem Happy Hacking!


English Here (machine translation)

abacus: 固定小数点数演算を行う算盤ユーティリティ

この C 言語ユーティリティは、金融演算などで利用されることの多い固定小数点数演算による計算手順を、整数部 18 桁、小数部 18 桁の精度で実行できます。(GO TO を含む) 計算手順はコマンド構造体 Commands_t の配列で指定します。


API を使用するためのヘッダは abacus.h で、API の実装は abacus.c です。API の説明は、この文書で後述しています。
テスト・プログラム abacus_test.c そして make ファイル Makefile も記述しました。


API の説明

  1. 固定小数点数演算を行う算盤ユーティリティ: abacus()
    int   abacus(chari      *result
    , size_t result_sz
    , size_t int_digits
    , size_t fra_digits
    , size_t memories_n
    , size_t commands_n
    , Command_t *commands
    , size_t *pc
    );

    result には最大 SZ_Numeral_str バイトの文字列バッファ・アドレスを渡します。
    result_sz には result の指すバッファのサイズを渡します。
    int_digits には result に出力する文字列の最大整数部桁数を指定します。
    fra_digits には result に出力する文字列の小数部桁数を指定します。
    memories_n には計算手順に必要な作業メモリの個数を指定します。
    commands_n には計算手順の手数 (commands 構造体配列の要素数) を指定します。
    commands には計算手順を次のマクロを使用して設定したコマンド構造体配列のアドレスを渡します。

    • Register0 : specify register#0 (result holder):

      最後に実行した計算手順の結果値を保持するレジスタをオペランドに指定する。

    • Memory(n) : specify working memory#n (n-th slot of working memories):

      オペランドに作業メモリのそれぞれを序数 0 〜 (memories_n - 1) で指定する。

    • Value(variable) : specify invoker's variable (invoker declared array of char, integer or enum):

      abacus() の呼び出し側が宣言している文字列バッファ (サイズは SZ_Numeral_str バイトでなければならない)、整数 (void ポインタのサイズを超えない整数型でなければならない)、丸めの方式 (How_to_rounding_e 列挙型) をオペランドに指定する。

    • Nop : no operation:

      演算は一切実行されず、次の手順に移る。

    • Ret(retcode) : return:

      手順を直ちに終了する。abacus() の戻り値は retcode になる。

    • Set(dst, src) : set value:

      dst に指定されたメモリ・オブジェクトに src に指定されたメモリ・オブジェクトの内容を転送する。

    • Jmp(steps) : jump:

      次に実行する計算手順を、現在の手順からの相対位置 steps に移動する。steps はゼロ以外の整数でなければならない。計算手順の配列を超えた位置に移動しようとした場合は、不正な引数エラーが起きる。

    • Cmp(a, b, less-case-steps, equals-case-steps, greater-case-steps) : compare and jump:

      値 a と b を比較した結果により、次に実行する計算手順に移動する。a < b ならば less-case-steps の示す相対位置へ、a = b ならば equals-case-steps の示す相対位置へ、a > b ならば greater-case-steps の示す相対位置へ次の計算手順を移動する。相対位置のそれぞれが、計算手順の配列を超えた位置に移動しようとした場合は、不正な引数エラーが起きる。

    • Sub(a, b) : subtract:

      値 a と b の差を求め、レジスタ Register0 に設定する。

    • Add(a, b) : add:

      値 a と b の和を求め、レジスタ Register0 に設定する。

    • Mul(a, b) : muliplies:

      値 a と b の積を求め、レジスタ Register0 に設定する。

    • Div(a, b, remainder) : divide and remainder:

      値 a と b の商を求め、レジスタ Register0 に設定する。remainder に Register0 あるいは Memory(n) を指定された場合は値 a と b の剰余も求め、レジスタあるいは指定された作業メモリに設定する。remainser に NO_Remainder が指定された場合は、剰余は求めない。
      特に、値 b は整数部と小数部の桁数の和が 18 桁を超えてはいけない。値 b に指定できる値は、次のようになる。

      -999999999999999999, -999999999999999998, ..., -99999999999999999.9, -99999999999999999.8, ...,
      ..., -1.00000000000000001, -1, -0.999999999999999999, -0.999999999999999998, ...,
      ..., -0.000000000000000002, -0.0000000000000000001, 0, 0.000000000000000001, 0.0000000000000000002, ...,
      ..., 0.999999999999999998, 0.999999999999999999, 1, 1.00000000000000001, ...,
      ..., 99999999999999999.8, 99999999999999999.9, ..., 999999999999999998, 999999999999999999

    • Rou(n, exp, how) : rounding:

      指数 exp (-18 〜 17) で指定された桁位置で値 n 丸めた値を求めレジスタ Register0 に設定する。丸めの方式は how に指定する。切り上げは Round_up (Value(ROUND_up) に等しい)、四捨五入は Round_even (Value(ROUND_even) に等しい)、切捨ては Round_down (Value(ROUND_down) に等しい) と定義している。

    pc には最後に実行した計算手順のコマンド配列上の要素位置を出力します。

    正常終了した場合、NORMAL_END がエラーに返され、最後に実行した計算手順の結果を int_digits と fra_digits に指定された整数部と小数部の桁数に編集した文字列を result に出力します。なんらかのエラーが発生した場合は、!NORMAL_END が戻り値に返ります。いずれの場合も、最後に実行した計算手順の commands 配列上の要素位置が pc に出力されます。

    発生したエラーの詳細は以下のように errno に出力されます。

    • EINVAL (= 22) : 不正な引数が渡された場合
    • ENOMEM (= 12) : 作業メモリに割り当てる動的メモリが獲得できない場合 (システムメモリ不足)
    • ERANGE (= 34) : 演算の結果あるいは演算途中の値が、整数部 18 桁、小数部 18 桁の精度を超えた場合
    • EDOM (= 33) : 演算に使用する値が定義域外になっている場合

      ※ Div() の除数 (値 b) は、整数部と小数部の桁数の和が 18 桁を超えてはいけません。