sys.float_info.min (とても小さい値) を代入しても何故か0.
になる。logが死ぬ。
データ型を疎かにしてたらハマった.
再現コード
float_array = numpy.array([1., 2.,], dtype=np.float32) tiny = sys.float_info.min print(float_array) # [1. 2.] float_array[1] = tiny print(float_array) # [1. 0.] # 0. …だと…!? match = float_array[1] == tiny print(f"float_array[1] == tiny: {match} ({float_array[1]} vs {tiny})") # float_array[1] == tiny: False (0.0 vs 2.2250738585072014e-308)
原因
Pythonにはfloatの更なる区分 (FP32/floatとFP64/doubleとか) がない.
でもnumpyには浮動小数点精度が複数ある.
sys.float_info.min
は内部で利用されてくる精度の値を出してくるけど、numpyは指定したdtypeで値を受け入れる.
float64の最小値をfloat32で表現すると0.
なので、0代入が発生しちゃう.
よくあるシチュエーション
外部ライブラリがnumpy arrayを返してくるが、そのデータ型を意識していない.
その状態でarrayの一部をsys.float_info.min
で上書きしようとしたのに、なぜか0.
になる.
結果logが死ぬ.
解決策
numpyを使うなら、使ってるdtypeの最小値を使えばいい.
float_array = numpy.array([1., 2.,], dtype=np.float32) false_tiny = sys.float_info.min true_tiny = np.finfo(float_array.dtype).tiny print(false_tiny) # 2.2250738585072014e-308 print(true_tiny) # 1.1754944e-38 float_array[1] = true_tiny print(float_array) # [1.0000000e+00 1.1754944e-38] match = float_array[1] == true_tiny print(f"float_array[1] == tiny: {match} ({float_array[1]} vs {true_tiny})") # float_array[1] == tiny: True (1.1754943508222875e-38 vs 1.1754943508222875e-38)
その他tips
Pythonのfloat精度は実行環境によるっぽい.
これが原因で「別の環境に持ってったら壊れた!?」とかはありうる.