nanって何なん
メモです
チェック環境 : Visual Studio 2015 Update 3
Releaseビルド
infからnanをつくる
const float nan = numeric_limits<float>::quiet_NaN(); const float inf = numeric_limits<float>::infinity(); printf("nan = %f\n", nan); printf("inf + inf = %f\n", inf + inf); printf("inf - inf = %f\n", inf - inf); printf("inf * inf = %f\n", inf * inf); printf("inf / inf = %f\n", inf / inf); [output] nan = nan inf + inf = inf inf - inf = -nan(ind) inf * inf = inf inf / inf = -nan(ind)
inf-infがnanっていうの、言われてみれば確かにって感じだった
nanをチェックする
printf("isNan(nan) = %s\n", isnan<float>(nan) ? "true" : "false"); printf("isNan(inf-inf) = %s\n", isnan<float>(inf-inf) ? "true" : "false"); [output] isNan(nan) = true isNan(inf-inf) = true
「nan」と「-nan(ind)」という表記ゆれがあったが、isnan()ではどっちもnan判定してくれるらしい
オーバーフローからinfをつくる
const float max = numeric_limits<float>::max(); printf("max = %f\n", max); for(int i=0; i<100; i++) { float x = max + pow(10.f, i); if( isinf(x) ) { printf("max + 10^%d -> inf\n", i); break; } } [output] max = 340282346638528859811704183484516925440.000000 max + 10^32 -> inf
オーバーフローによるinf化、maxに足して起こるのは10^32ぐらいが目安
ヒープ汚れによる初期値nan
class A { public: explicit A() {} public: float a, b, c; }; { A* class_a = new A(); class_a->a = class_a->b = class_a->c = nan; printf("1: addr=%p a=%f b=%f c=%f\n", class_a, class_a->a, class_a->b, class_a->c); delete class_a; } { A* class_a = new A(); // メンバ初期化しない printf("2: addr=%p a=%f b=%f c=%f\n", class_a, class_a->a, class_a->b, class_a->c); delete class_a; } [output] // だいたいこんな感じになる 1: addr=00919F28 a=nan b=nan c=nan 2: addr=00919E68 a=0.000000 b=0.000000 c=0.000000 // だが、15回に1回ぐらいの頻度で同じアドレスにメモリを確保し、初期値がnanになる 1: addr=00DEA200 a=nan b=nan c=nan 2: addr=00DEA200 a=nan b=nan c=nan
絶対に変数初期化しような
平方根、指数、対数
const float min = -max; const float eps = numeric_limits<float>::epsilon(); printf("sqrt(-eps) = %f\n", sqrt(-eps)); printf("sqrt(inf) = %f\n", sqrt(inf)); printf("exp(max) = %f\n", exp(max)); printf("exp(inf) = %f\n", exp(inf)); printf("log(0) = %f\n", log(0.f)); printf("log(-eps) = %f\n", log(-eps)); printf("log(inf) = %f\n", log(inf)); [output] sqrt(-eps) = -nan(ind) // 少しでも負ならnan化 sqrt(inf) = inf exp(max) = inf // inf化 exp(inf) = inf // めちゃくちゃ大きくなるが、数値ではあるのでnanではない log(0) = -inf // 0なら-inf log(-eps) = -nan(ind) // 少しでも負なら未定義 -> nan log(inf) = inf // logは収束しそうな形してるけど収束しない
ちなみにnan突っ込んだときは全部nanになる (伝播する)