/**
* 定数 NANと比較すると偽を返すこと。
*
* NaNかどうか判定するために、定数 NANと比較してはならない。
*/
public void testCompareNanAndNan() {
/* 事前条件の準備 */
double value = NAN;
/* 実行 */
boolean result = (value == NAN);
/* 事後条件の検証 */
Assert_false("結果は偽であること。", result);
}
これを実行すると、テストは成功する。変数 valueが定数 NANで初期化されているが、その変数を NANと比較しても真にならない。
比較演算子で NANと比較しても NaNかどうか判断できないということで、これは正しい挙動である。
なお、このテストケースは gccを使用してコンパイルしたが、定数 NANを使用するためには math.hをインクルードする必要がある。
ISOの C99よりも前のバージョンでは、処理系によっては NANが使えない。
/**
* NaNであることを判定できること。
*
* NaNかどうかの判定には isnan()を使用すること。
*/
public void testIsNan() {
/* 事前条件の準備 */
double value = NAN;
/* 実行 */
boolean result = isnan(value);
/* 事後条件の検証 */
Assert_true("結果は真であること。", result);
}
isnan()も math.hが必要。/**
* ポインタを使用して NANと比較することで、NaNかどうかを判定できること。
*
* この使い方を推奨しているわけではないが、定数を代入しただけのものは
* ビットパターンの比較により判断ができる。
* この例ではポインタを使用したが、unionを用いても同様のことができる。
*
* NaNの値は1通りではないため、計算結果や外部から読み込んだ値を正しく
* 判断するには == は使えない。
*/
public void testCompareNanAsPointer() {
/* 事前条件の準備 */
double value = NAN;
double nan = NAN;
/* 実行 */
boolean result = (*(long long*)&value == *(long long*)&nan);
/* 事後条件の検証 */
Assert_true("結果は真であること。", result);
}
ドキュメントコメントにも書いてあるよう、この方法では特定の条件でした判断できない。/**
* NaNは 指数部の全ビットが 1で、仮数部が 0でないこと。
*
* これは例を示しただけで、実際にやるのは無駄。 isnan()を使うべき。
*/
public void testNanAsPattern() {
/* 事前条件の準備 */
double value = NAN;
long long exponentMask = 0x7ff0000000000000;
long long mantissaMask = 0x000fffffffffffff;
/* 実行 */
long long longValue = *(long long*)&value;
boolean result = ((longValue & exponentMask) == exponentMask)
&& ((longValue & mantissaMask) != 0);
/* 事後条件の検証 */
Assert_true("結果は真であること。", result);
}
valueを定数 NANで初期化したものだけでなく、0.0 / 0.0した結果も正しく判断できる。printfを使って調べると、gccの場合、NANのパターンは 0x7ff8000000000000、0.0 / 0.0の結果は 0xfff8000000000000で 1ビット異なるが、いづれも NaNと判定できた。
注:value = 0.0 / 0.0; というコードはコンパイル時点でエラーになる。 分母を変数にしてその変数を 0.0で初期化するようにすれば、コンパイルが通るようになる。
普段の判定は isnan()を使用すればよいが、isnan()が使えない場合や NaNを使ったテストケースを記述するとき、この知識は役にたつだろう。
これらのテスト関数はつぎのようなコードを含むソースコードとして記述され、softiesの CUnitライブラリとリンクされる。
#define import_lwd_unit_Assert
#define import_lwd_unit_CUnit
#include <lwd/lwd.h>
#include <lwd/unit/Assert.h>
#include <lwd/unit/CUnit.h>
#include <math.h>
/**
* @file
*
* NaNの振る舞いのテスト。
*/
/****************************************************************
test cases
****************************************************************/
// ここに、テスト関数を記述する。
// テスト関数名が異なれば複数個記述可能。
/****************************************************************
main
****************************************************************/
public int main(int argc, char** argv) {
return CUnit_test(argc, argv);
}
main関数のなかで CUnit_test()を呼び出すことにより、自動的にテスト関数を認識して実行する。なおテスト関数の名前は textXXXのように先頭4文字は testでなければならない。