大阪市中央区 システムソフトウェア開発会社

営業時間:平日09:15〜18:15
MENU

C++でC風ライブラリを作る(商と剰余編)

著者:高木信尚
公開日:2019/02/10
最終更新日:2019/02/10
カテゴリー:技術情報

高木です。おはようございます。

前回は絶対値編でした。
元ネタはstdlib.hヘッダのabs関数ですので、今回は同じヘッダのdiv関数を元ネタにしたいと思います。

div関数にも型によってバリエーションがあり、ldivlldivimaxdivといったものが挙げられます。
どういうわけか符合無し整数型に対応した関数がありません。
符合付き整数と符合無し整数が混在した場合はちょっと面倒なので、その辺りは念入りに検討する必要がありそうです。

abs関数と同様の理由でオーバーフローが発生することもあります。
具体的には、INT_MINを-1で割った場合に発生します。
また、ゼロ除算の問題も当然あります。

div_tという構造体にも汎用性がありません。
テンプレートで利用しようとしたとき、引数の型によって返却値がdiv_tldiv_tなどを使い分ける必要があるからです。
型推論を使えばマシにはなりますが、ハッキリいってイケていません。

ボリュームが増えそうな引数の型が混在したケースは次回まわしにして、今回は2つの引数の型が同じ場合にしぼって考えることにします。
同じ型の2つの引数取る関数を多重定義した場合、(汎整数昇格したあとの)型が異なる実引数を渡そうとすると多重定義が解決できずにエラーになります。
うっとうしく感じることもありますが、うっかりミスをやってしまうよりはエラーにしてしまったほうが間違いがありません。

エラー処理に関しては例外を使うことにします。
ゼロ除算とオーバーフローについてです。
ゼロ除算の場合はstd::invalid_argumentを、オーバーフローの場合はstd::overflow_errorを送出することにしましょう。

返却値の型はcloverfield::div_tクラステンプレートを定義して、それを使うことにします。
まずはこのクラステンプレートの定義から進めることにしましょう。

標準Cライブラリでは、このquotremの順序が処理系定義でした。
そういうところが使い勝手の悪さにつながっています。
今回は順序は固定ですので、それだけでもずいぶん扱いやすくなります。

次に実際の関数の定義を行います。
今回は代表してintunsigned intの2つの型だけを掲載しますが、実際には他の型についても同様に定義することになります。

まずは、比較的簡単なunsigned int版から見ていきましょう。

unsigned int版ではオーバーフローが発生することはありませんので、ゼロ除算だけ判定しています。

次はint版です。

ゼロ除算とオーバーフローを検出しないとイケませんので若干複雑になりました。

浮動小数点型については作成を見送りました。
constexprにするのが面倒なので、対称性に欠けるからです。
頑張ればconstexprにすることも可能ですが、truncfmodといった関数のconstexpr版を先に作成する必要がありそうです。
それらの関数を作成する機会があれば、その時点で着手してもよいでしょうね。

    上に戻る