ぼくのかんがえたさいきょうのround関数

浮動小数点数の丸めにおいて丸め桁数を指定でき、それでいて精度を失わないようなround関数をCで実装してみました。


実装としては、受け取った浮動小数点数から最短になる10進表記に変換し、浮動小数点をズラすことなく10進表記のまま四捨五入を行うものです。これを元に偶数丸めを実装するのも容易でしょう。


実際、前回記事「RubyとPythonとC#のround関数のバグっぽい挙動について」で指摘した5.015の例についても期待通りに丸めることができます。

#include <stdio.h>

extern double precise_round(double x, int digits);

int main()
{
  printf("%f\n", precise_round(5.015, 2)); // 5.02
  printf("%f\n", precise_round(5.0149999999999987921, 2)); // 5.01
}

浮動小数点数とその10進表記の正確な相互変換は1990年の論文で決着済み

浮動小数点数とその10進表記との間で最も近い数に変換する方法は「How to Read Floating Point Numbers Accurately *1」「How to Print Floating-Point Numbers Accurately *2」という論文で示されています。また、この論文を元にしてDavid M. Gayが実装したdtoa.cは、多くのオープンソースプロジェクトで利用されています。


前回記事で紹介したMySQLの処理でも浮動小数点数から最短の10進表記を作り出していますが、この処理には上記dtoa.cの改変版が利用されています。ちなみに僕の今回の実装はオリジナルのdtoa.cをそのまま利用しました。

*1:William D Clinger, "How to Read Floating Point Numbers Accurately", ACM SIGPLAN '90, pp.92--101, 1990. (同じ論文のretrospective版のPDF版

*2:Guy L. Steele, Jr. and Jon L. White, "How to Print Floating-Point Numbers Accurately", ACM SIGPLAN '90, pp.112--126, 1990. (同じ論文のretrospective版のPDF版

続きを読む