最終更新: 2022/1/6

内部型の異なる区間同士の変換

柏木 雅英

1. はじめに

interval<double>とinterval<dd>など、 内部型の異なる区間同士の変換は、代入する側の型が 代入される側の型の完全な部分集合でもない限りそのまま代入することはできず、 下端は下向き丸め、上端は上向き丸めで変換し代入する必要がある。

今まできちんとdocumentに書いていなかったが、混合精度でプログラムを作る必要に 迫られてこれを行う機能は存在していた。 version 0.4.54で少しきれいに整備したので、古い方法、新しい方法に分けて 説明する。 古い方法も互換性のために残しておくが、将来は 削除する可能性がある。

2. 古い(version 0.4.53以前)の方法

#include <kv/interval-conv.hpp>
のようにincludeすると、double, dd, mpfrを内部に持つ区間の間の 相互変換ができるようになる。例えば、
        kv::interval< kv::mpfr<106> > x;
        kv::interval<kv::dd> y;

        kv::impfrtoidd(x, y);
のようにすれば、mpfr型を内部に持つ区間xの値を、dd型を内部に持つ区間yに 適切な丸めを行いながら代入することができる。

以下の表の関数が使える。

src \ dst double dd mpfr
double - idoubletoidd idoubletoimpfr
dd iddtoidouble - iddtoimpfr
mpfr impfrtoidouble impfrtoidd impfrtoimpfr

(impfrtoimpfrは、異なる精度のmpfr同士の変換に使う)

これらの関数は内部で以下のようなdouble, dd, mpfr相互の丸め方向指定付き 代入関数を使っている。これらを直接呼び出しても構わない。

        kv::mpfr<106> x;
        kv::dd y;

        kv::mpfrtodd(x, y, 0);
        kv::mpfrtodd(x, y, -1);
        kv::mpfrtodd(x, y, 1);
(0はnearestまたはそれに近い動作、-1は下向き丸め、1は上向き丸め)

src \ dst double dd mpfr
double - - -
dd ddtodouble - ddtompfr
mpfr mpfrtodouble mpfrtodd mpfrtompfr

(mpfrtompfrは、異なる精度のmpfr同士の変換に使う)

test-inverval-conv.cc は上記関数の使用例になっている。

3. 新しい(version 0.4.54以降)の方法

古い方法は 関数名に型名を含んでいる設計がC++らしくない。 version 0.4.54で新しく、_Float64, ddxという新しい型をサポートするにあたって、 少しきれいに整理してみた。

#include <kv/interval-converter.hpp>
のようにincludeすると、double, dd, mpfr, _Float64x, ddxを内部に持つ 区間同士で、
        kv::interval< kv::mpfr<106> > x;
        kv::interval<kv::dd> y;

	y = x;
のように普通に代入するだけで適切な丸めを伴った変換ができるようになった。

また、その内部で使用されている double, dd, mpfr, _Float64x, ddx同士の変換関数も、

        kv::mpfr<106> x;
        kv::dd y;

        kv::rounded_converter(x, y, 0);
        kv::rounded_converter(x, y, -1);
        kv::rounded_converter(x, y, 1);
のように"rounded_converter"という1つの関数名で、引数の型に応じて 適切なものが呼ばれるようになった。 この5つ以外の新たな内部型を追加したい場合でも、 引数でオーバーロードされたrounded_converter 関数を適切に定義してやるだけでOKなはず。

test-inverval-converter.cc は上記関数の使用例になっている。