2017/03/10(金)kv-0.4.41
今回の変更は、キャストし忘れでode solverの内部使用型をddとしたときにコンパイル出来なくなっていた修正だけです。
また、ドキュメントにkvライブラリの応用例のページを追加しました。まだ2つだけしか載せていませんが、手元には載せたい応用例がたくさんあるので今後増やしていきたいと思います。また、このページでは数式を表示するプラグインのMathJaxを使ってみました。何か不具合があればお知らせください。
a=21023の場合、a+bがオーバーフローしてしまう問題があります。
b=21023
a=2-1074のとき、a*0.5、b*0.5はともにアンダーフローで0になってしまい、結果も0になってしまいます。
b=2-1074
a=21023でオーバーフローしてしまいます。
b=-21023
a=5*2-1074としてみましょう。このとき、IEEE754の偶数丸めルールの関係で、
b=7*2-1074
a*0.5=2*2-1074となります。よって計算結果は7*2-1074となってしまい、真の6*2-1074になりません。
b*0.5=4*2-1074
a=(253-1)*2-1073とすると、
b=7*2-1074
(nearest)=2-1021+2-1073と値がずれてしまいます。a*0.5は無誤差ですが、b*0.5と加算で両方上向き丸めになった結果、真値(2-1021+2-1073+2-1075)を丸めたものとずれてしまいました。
(計算値)=2-1021+2-1072
midrad(I, m, r);とすると中心の近似mと、半径rを同時に計算します。これは、中心m、半径rの区間で I を包含する、すなわち、上端下端型の区間から中心半径型の区間への変換に使われることを意図しています。単純に
m = mid(I);とすれば良さそうなものですが、中心mに丸め誤差が入るので、これだと I を包含しない可能性があるのです。例えば、ε=2-52として、I=[1,1+3ε]とします。このとき、midとradを別々に計算すると、
r = rad(I);
m = 1+2εとなりますが、[m-r,m+r]は I を含まないことが分かります。midradを使うと、ちゃんと
r = 1.5ε
m = 1+2εになります。ミスが起こりやすいポイントなので気をつけて下さい。
r = 2ε
max([a,b],[c,d]) = [max(a,c),max(b,d)]のように行います。
min([a,b],[c,d]) = min(a,c),max(b.d)]
#include <kv/interval.hpp> #include <kv/rdouble.hpp> typedef kv::interval<double> itv; using namespace std; int main() { cout << max(itv(2., 4.), itv(3., 5.)) << endl; cout << min(itv(3., 5.), itv(2., 4.)) << endl; }のようなプログラムを動かすと、予想に反して
[2,4]という結果が帰って来ます。これは、std::max, std::minが呼び出されてしまっており、恐らくmaxは
[3,5]
template <class T> T max(const T& a, const T& b) { return (a < b) ? b : a; }のような実装になっていて、[2,4]<[3,5]は偽なので[2,4]が返されてしまっていると推測されます。よく考えれば分かるとは言え、これは事故を誘発しやすいので、ちゃんと区間用のmaxとminを実装しました。kv-0.4.38で上のプログラムを動かすと、ちゃんと
[3,5]となります。
[2,4]
#define NOMINMAX #include <windows.h>のようにwindows.hをincludeする前にNOMINMAXを定義して下さい。