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

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

C++でC風ライブラリを作る(絶対値編)

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

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

今回は絶対を求める関数を設計&実装したいと思います。
Cの標準ライブラリには、整数用のabslabsllabsimaxabs関数があります。
また、実浮動小数点枢要にfabsffabsfabsl関数があります。
さらに、複素数用にcabsf、cabs、cabsl関数があります。

このうち、複素数用はちょっと用途が異なりますし、C++では複素数はstd::complexクラステンプレートを使うということもあって今回は対象外にします。
必要ならあとから追加することもできますからね。
というわけで、今回は(虚数ではなく)実数の絶対値だけを考えることにします。

絶対値を求める関数のうち、浮動小数点用のものについてはとくに不満はありません。
しかし、整数用のものについては結構不満があります。

整数用の絶対値関数の最大の不満は、絶対値を求めているのに結果が負になってしまうことがある点です。
厳密にいえばオーバーフローが発生して未定義の動作になっているのですが、現実に遭遇する処理系では負の値が返ってきます。
具体的には、int型用のabs関数にINT_MINを指定した場合がそうです。

この問題を解決するには、次の3つの方法が考えられます。

  • 返却値を引数より大きな型とすることで、オーバーフローが発生しないようにする。
  • 返却値を符合無し整数型とする。
  • オーバーフローが生じた場合に例外を送出する。

多くの言語では3番目の解決方法、すなわちオーバーフローが生じた場合に例外を送出する設計を採用しているようです。
それでもいいんですが、できれば失敗しない関数にしたいという希望もあります。
だとすると、1番目か2番目の方法になってきます。

1番目の方法は、int型より小さい型については適切な選択だと思います。
しかし、long long型の場合はそれ以上大きな型がありません。
浮動小数点数を使う手もありますが、精度が落ちてしまう可能性がありますのでダメです。

2番目の方法については、引数と型が変わってしまうことを除けば大きな問題はありません。
というわけで、今回は2番目のと3番目の方法それぞれについて、cloverfield::abs関数とcloverfield::uabs関数を作成したいと思います。

作成にあたり、SFINAEを使うなど凝った技法を使いたくなったりもするのですが、今回の趣旨はなるべくシンプルに設計&実装することですので方針が合いません。
そこで、ベタベタに関数の定義を書き並べることにしましょう。
intlonglong long型とそれらに対応するunsigned、およびfloatdoublelong double型について関数を定義することになります。

全部掲載すると多いので、代表してintunsigned intdoubleの3つだけを掲載することにします。
簡単なものから掲載していきますので、最初はunsigned int型からです。

次はdouble型です。

ここまでは簡単ですね。

最後はint型です。
ここで一気に複雑になります。
この手のconstexpr関数を書くにはC++11は面倒ですが、まあ仕方ありません。

ちょっと横に長くなってしまいましたが、どこで改行してもとくに見やすくならないのでそのまま掲載します。

こうして定義した関数群をヘッダファイル(cloverfield/stdlib.hhという名前が妥当ですかね)に収めればできあがりです。

    上に戻る