関数doublecmp マニュアル

(The documentation of function doublecmp)

Last Update: 2021/12/27


◆機能・用途(Purpose)

2つのdouble型変数の大小関係を調べる。
Compare two double-type variables.


◆形式(Format)

#include <doublemath.h>
inline int doublecmp(const double a,const double b)


◆引数(Arguments)

a 比較したい一方の実数。
One of the real numbers to be compared.
b 比較したいもう一つの実数。
The other one of the real numbers to be compared.


◆戻り値(Return value)

但し\(a\)と\(b\)が非常に近い値の場合は厳密に等しくなくても\(a=b\)と見なす。 詳しくは下記「判定方法」参照。
When \(a\) and \(b\) are very close to each other, it is regarded that \(a=b\), even if they are not exactly equal. For detail, see “Judgements” section below.


◆使用例(Example)

double a,b;
if(doublecmp(a,b)>0){
    printf("a>b\n");
}else if(doublecmp(a,b)==0){
    printf("a=b\n");
}else{
    printf("a<b\n");
}


◆判定方法(Judgements)

浮動小数点数では内部のビット表現の問題により、 本当は等しい2つの実数が僅かに異なる値を持つ場合がある。 例えば論理式
    (1.0/3.0)∗3.0==1.0
はfalseとなる。 そこでこの関数では完全に\(a=b\)でなくとも \(a\)と\(b\)の差がある閾値以下であれば\(a=b\)であると見なす。 その閾値のもとで\(a < b\)と見なされた場合は\(-1\)、 \(a=b\)と見なされた場合は0、 \(a > b\)と見なされた場合は1を返す。
Due to internal expressions of floating-point variables, two real numbers which are equal may have slightly different values to each other. For example, a logical formula
    (1.0/3.0)∗3.0==1.0
gives false. In this function, \(a\) and \(b\) are regarded to be equal if the difference between them is below a threshold level, even if they are not exactly equal. The return values are \(-1\), 0, and 1 if it is regarded that \(a < b\), \(a=b\), and \(a > b\), respectively, based on comparisons of the differences to the threshold level.

\(a=b\)であると見なす基準としては \[\begin{equation} \frac{|a-b|}{\frac{|a|+|b|}{2}} < ZERO\_THRESHOLD \label{eq.criterion} \end{equation}\] を用いている (ZERO_THRESHOLDはmacro.hで定義されたマクロ)。 但し、0による割り算を防ぐため、 \(\frac{|a|+|b|}{2} \leq 0\)の場合は別扱いで0を返すようにしている。 これが成り立つのは厳密に\(a=b=0\)の場合だけであるので0を返して問題無い。
For a threshold to regard as \(a=b\), eq. (\ref{eq.criterion}) is used, where ZERO_THRESHOLD is a macro defined in macro.h. To avoid a division by 0, the return value of this function is set to 0 in case of \(\frac{|a|+|b|}{2} \leq 0\). This operation is validated by noticing that the condition \(\frac{|a|+|b|}{2} \leq 0\) holds only when strictly \(a=b=0\).

(\ref{eq.criterion})式の左辺の分母\(\frac{|a|+|b|}{2}\)は \(a\),\(b\)の値そのものの大きさのスケールの目安と思えば良い。 例えば\(ZERO\_THRESHOLD=10^{-6}\)とした場合、 \(|a-b|\)が\(a\),\(b\)の大きさのスケールと比較しておおよそ6桁程度小さければ 事実上\(a=b\)と見なすというのが(\ref{eq.criterion})の意味するところである。 このような基準を用いているので 結果は\(a\)や\(b\)の値そのもののスケールには依存しない。 すなわち任意の正定数\(c\)について、 doublecmp(a,b)とdoublecmp(c*a,c*b)は同じ結果を返す。
The denominator of the left hand side of eq. (\ref{eq.criterion}), i.e., \(\frac{|a|+|b|}{2}\), can be regarded to be a measure of the scales of \(a\) and \(b\). For example, when \(ZERO\_THRESHOLD=10^{-6}\), eq. (\ref{eq.criterion}) means that \(a\) and \(b\) are regarded to be equal when the difference \(|a-b|\) is smaller than the scales of \(a\) and \(b\) by a factor of \(\sim 10^6\). Using this criterion, the result is independent of the scales of \(a\) and \(b\); doublecmp(a,b) and doublecmp(c*a,c*b) returns exactly the same values for arbitrary positive constants \(c\).

例外として、\(a\)と\(b\)のどちらか片方が厳密に0.0の場合には もう片方の絶対値がZERO_THRESHOLDよりも小さければ\(a=b\)と見なす。 例えば厳密に\(b=0.0\)の場合には \(|a|<ZERO_THRESHOLD\)ならば\(a=b\)と見なす。 そうしないとif(doublecmp(a,0.0)==0){}のような判定文は aにほんの僅かでも数値誤差があれば成り立たなくなるからである。
An exception is that when one of \(a\) or \(b\) is exactly 0.0 and the absolute value of the other is less than ZERO_THRESHOLD, \(a\) and \(b\) are regarded to be equal. For example, when \(b\) is exactly 0.0 and \(|a|<ZERO_THRESHOLD\), \(a\) is regarded to be equal to \(b\). This is because otherwise a very slight numerical error in \(a\) results in a failure of judgement for if(doublecmp(a,0.0)==0){}.