うちのマシンは、int64じゃない!?

numpyのデータタイプ

これから、Numpyを使っていろいろと演算等を行うにあたって自分が何をやっているのか知っておく必要がある
つまり、π(パイ)はいくつなんだ?という話なのである。(実際は、いくつとしてデータに記録されるのかという話)

事の始まり

import numpy as np
def ndarray_info(np_array):
    print("配列の軸数(次元) = ",np_array.ndim)
    print("各次元の配列のサイズ = ",np_array.shape)
    print("要素の総数 = ",np_array.size)
    print("要素の形式 = ",np_array.dtype)
    print("1要素のbyte数 = ",np_array.itemsize)

print("-- a --")
a = np.array([1,2,3])
ndarray_info(a)
print("-- b --")
b = np.array([1.2,2.3,3.4])
ndarray_info(b)
-- a --
配列の軸数(次元) =  1
各次元の配列のサイズ =  (3,)
要素の総数 =  3
要素の形式 =  int32
1要素のbyte数 =  4
-- b --
配列の軸数(次元) =  1
各次元の配列のサイズ =  (3,)
要素の総数 =  3
要素の形式 =  float64
1要素のbyte数 =  8

うぅ?
あれ、、、、、要素の形式 = int32 ってなんでint64じゃないの?

import sys
print("Python version =",sys.version)
print("Python platform =",sys.platform)
print("Python intger=",sys.int_info)
print("Python float =",sys.float_info)
Python version = 3.7.3 (default, Mar 27 2019, 17:13:21) [MSC v.1915 64 bit (AMD64)]
Python platform = win32
Python intger= sys.int_info(bits_per_digit=30, sizeof_digit=4)
Python float = sys.float_info(max=1.7976931348623157e+308, max_exp=1024, max_10_exp=308, min=2.2250738585072014e-308, min_exp=-1021, min_10_exp=-307, dig=15, mant_dig=53, epsilon=2.220446049250313e-16, radix=2, rounds=1)

Python自体は、タスクマネージャーを見る限り64bitプログラムとして動ている。プラットフォームがwin32なのが気になるが。
intは、4byteで32bitなのね。floatは、8byteで64bitみたいだ。min_10_exp=-307, dig=15, mant_dig=53が、倍精度浮動小数点数とちょっと違うが表現の違いだけなのだろう。
で、Numpyはどうなのか?

import numpy as np
print("np.float => ",np.finfo(np.float))
print("np.float_ => ",np.finfo(np.float_))
print("np.float32 => ",np.finfo(np.float32))
print("np.float64 => ",np.finfo(np.float64))
print("np.single => ",np.finfo(np.single))
print("np.double => ",np.finfo(np.double))
print("np.longdouble => ",np.finfo(np.longdouble))
print("float => ",np.finfo(float))  # floatは、OKみたいだ
np.float =>  Machine parameters for float64
---------------------------------------------------------------
precision =  15   resolution = 1.0000000000000001e-15
machep =    -52   eps =        2.2204460492503131e-16
negep =     -53   epsneg =     1.1102230246251565e-16
minexp =  -1022   tiny =       2.2250738585072014e-308
maxexp =   1024   max =        1.7976931348623157e+308
nexp =       11   min =        -max
---------------------------------------------------------------

np.float_ =>  Machine parameters for float64
---------------------------------------------------------------
precision =  15   resolution = 1.0000000000000001e-15
machep =    -52   eps =        2.2204460492503131e-16
negep =     -53   epsneg =     1.1102230246251565e-16
minexp =  -1022   tiny =       2.2250738585072014e-308
maxexp =   1024   max =        1.7976931348623157e+308
nexp =       11   min =        -max
---------------------------------------------------------------

np.float32 =>  Machine parameters for float32
---------------------------------------------------------------
precision =   6   resolution = 1.0000000e-06
machep =    -23   eps =        1.1920929e-07
negep =     -24   epsneg =     5.9604645e-08
minexp =   -126   tiny =       1.1754944e-38
maxexp =    128   max =        3.4028235e+38
nexp =        8   min =        -max
---------------------------------------------------------------

np.float64 =>  Machine parameters for float64
---------------------------------------------------------------
precision =  15   resolution = 1.0000000000000001e-15
machep =    -52   eps =        2.2204460492503131e-16
negep =     -53   epsneg =     1.1102230246251565e-16
minexp =  -1022   tiny =       2.2250738585072014e-308
maxexp =   1024   max =        1.7976931348623157e+308
nexp =       11   min =        -max
---------------------------------------------------------------

np.single =>  Machine parameters for float32
---------------------------------------------------------------
precision =   6   resolution = 1.0000000e-06
machep =    -23   eps =        1.1920929e-07
negep =     -24   epsneg =     5.9604645e-08
minexp =   -126   tiny =       1.1754944e-38
maxexp =    128   max =        3.4028235e+38
nexp =        8   min =        -max
---------------------------------------------------------------

np.double =>  Machine parameters for float64
---------------------------------------------------------------
precision =  15   resolution = 1.0000000000000001e-15
machep =    -52   eps =        2.2204460492503131e-16
negep =     -53   epsneg =     1.1102230246251565e-16
minexp =  -1022   tiny =       2.2250738585072014e-308
maxexp =   1024   max =        1.7976931348623157e+308
nexp =       11   min =        -max
---------------------------------------------------------------

np.longdouble =>  Machine parameters for float64
---------------------------------------------------------------
precision =  15   resolution = 1.0000000000000001e-15
machep =    -52   eps =        2.2204460492503131e-16
negep =     -53   epsneg =     1.1102230246251565e-16
minexp =  -1022   tiny =       2.2250738585072014e-308
maxexp =   1024   max =        1.7976931348623157e+308
nexp =       11   min =        -max
---------------------------------------------------------------

float =>  Machine parameters for float64
---------------------------------------------------------------
precision =  15   resolution = 1.0000000000000001e-15
machep =    -52   eps =        2.2204460492503131e-16
negep =     -53   epsneg =     1.1102230246251565e-16
minexp =  -1022   tiny =       2.2250738585072014e-308
maxexp =   1024   max =        1.7976931348623157e+308
nexp =       11   min =        -max
---------------------------------------------------------------

このプラットフォームが扱えるNumpyの浮動小数点は、float32(single)float64(double)の2種類か
floatはfloat64と置き換えられるみたいだ

import numpy as np
print("np.int => ",np.iinfo(np.int))
print("np.byte => ",np.iinfo(np.byte))
print("np.ubyte => ",np.iinfo(np.ubyte))
print("np.short => ",np.iinfo(np.short))
print("np.ushort => ",np.iinfo(np.ushort))
print("np.intc => ",np.iinfo(np.intc))   # C言語ライブラリのint
print("np.uintc => ",np.iinfo(np.uintc)) # C言語ライブラリのuint
print("np.int_ => ",np.iinfo(np.int_))
print("np.uint => ",np.iinfo(np.uint))
print("np.longlong => ",np.iinfo(np.longlong))
print("np.ulonglong => ",np.iinfo(np.ulonglong))
print("int => ",np.iinfo(int))  # intは、OKみたいだ
np.int =>  Machine parameters for int32
---------------------------------------------------------------
min = -2147483648
max = 2147483647
---------------------------------------------------------------

np.byte =>  Machine parameters for int8
---------------------------------------------------------------
min = -128
max = 127
---------------------------------------------------------------

np.ubyte =>  Machine parameters for uint8
---------------------------------------------------------------
min = 0
max = 255
---------------------------------------------------------------

np.short =>  Machine parameters for int16
---------------------------------------------------------------
min = -32768
max = 32767
---------------------------------------------------------------

np.ushort =>  Machine parameters for uint16
---------------------------------------------------------------
min = 0
max = 65535
---------------------------------------------------------------

np.intc =>  Machine parameters for int32
---------------------------------------------------------------
min = -2147483648
max = 2147483647
---------------------------------------------------------------

np.uintc =>  Machine parameters for uint32
---------------------------------------------------------------
min = 0
max = 4294967295
---------------------------------------------------------------

np.int_ =>  Machine parameters for int32
---------------------------------------------------------------
min = -2147483648
max = 2147483647
---------------------------------------------------------------

np.uint =>  Machine parameters for uint32
---------------------------------------------------------------
min = 0
max = 4294967295
---------------------------------------------------------------

np.longlong =>  Machine parameters for int64
---------------------------------------------------------------
min = -9223372036854775808
max = 9223372036854775807
---------------------------------------------------------------

np.ulonglong =>  Machine parameters for uint64
---------------------------------------------------------------
min = 0
max = 18446744073709551615
---------------------------------------------------------------

int =>  Machine parameters for int32
---------------------------------------------------------------
min = -2147483648
max = 2147483647
---------------------------------------------------------------

このプラットフォームが扱えるNumpyの整数は、8,16,32,64bit長の符号有り無しみたいだintはint32と置き換えられる
(この、マシン環境ではintはint64にならないMPUが古いから?)

まとめ

Numpyで使用されているデフォルトの形式を理解しておく必要がある。LinuxWindowsまたはMPUの違いにより基礎となるC演算ライブラリ等が変わってくるからである。同じプログラムソースでもnp.array(raw)で作られる内部データ形式(dtype)がint32,int64やfloat32,float64と違う場合があるので演算結果に相違が出てくる場合がある。掛け算の掛け算とか総和を求める関数とかオーバーフローを起こしたり丸目誤差問題が発生したりなどである。最近のMPUであればint64,float64になっているので大きな数字を扱えるのでほとんど気にしないのかな?

(SSE関係は実装されているがAVX関係は実装されてないんだよなぁこのMPUだからなのかなぁ?普通にWindows 10なんだけど) 追記:stackoverflowに、同様の質問がありその結果は、LinuxMacOSは、int64になっているがWindowsはint32だということ。 int_ Default integer type (same as C long; normally either int64 or int32) とのことで、windowsが定義しているC言語ライブラリがlongがint32でたのOSはlongはint64なのでそうなっているとのこと うちのマシンが古すぎるせい!ってわけでなくよかったよ。

蛇足

import numpy as np
pi_str = "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679"
pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
pi2 = 31415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
print("python π = ",pi_str,type(pi_str))

print("=== Python(Myマシン) ===")
print("python π = ", pi,type(pi))
print("python 101桁pi2 = ",pi2,type(pi2))
pi3 = pi2 +1
print("python 101桁pi2 +1 = ",pi3,type(pi3))
piar = [pi]
piar2 = [pi2]
print("python array piar[0] = ", piar[0],type(piar[0]))
print("python array piar2[0] = ", piar2[0],type(piar2[0]))

print("=== Numpy float(Myマシン) ===")
nppi = np.empty((1))
nppi[0] = pi
print("np.array(π) = ",nppi,nppi.dtype)
nppi_f64 = np.empty((1),dtype=np.float64)
nppi_f64[0] = pi
print("np.array(π,dtype=np.float64) = ", nppi_f64,nppi_f64.dtype)
nppi_f32 = np.empty((1),dtype=np.float32)
nppi_f32[0] = pi
print("np.array(π,dtype=np.float32) = ", nppi_f32,nppi_f32.dtype)
nppi_f16 = np.empty((1),dtype=np.float16)
nppi_f16[0] = pi
print("np.array(π,dtype=np.float16) = ", nppi_f16,nppi_f16.dtype)
nppi_i = nppi.astype(np.int64)
print("np.array(π).astype(np.int64) 整数化 = ",nppi_i,nppi_i.dtype)


print("=== Numpy integer(Myマシン) ===")
nppi2 = np.array(piar2)
print("np.array(101桁整数) = ",nppi2,nppi2.dtype)
nppi_i32 = np.array(piar2,dtype=np.int32)
print("nppi_i32 = ",nppi_i32,nppi_i32.dtype)
python π =  3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679 <class 'str'>
=== Python(Myマシン) ===
python π =  3.141592653589793 <class 'float'>
python 101桁pi2 =  31415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679 <class 'int'>
python 101桁pi2 +1 =  31415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170680 <class 'int'>
python array piar[0] =  3.141592653589793 <class 'float'>
python array piar2[0] =  31415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679 <class 'int'>
=== Numpy float(Myマシン) ===
np.array(π) =  [3.14159265] float64
np.array(π,dtype=np.float64) =  [3.14159265] float64
np.array(π,dtype=np.float32) =  [3.1415927] float32
np.array(π,dtype=np.float16) =  [3.14] float16
np.array(π).astype(np.int64) 整数化 =  [3] int64
=== Numpy integer(Myマシン) ===
np.array(101桁整数) =  [31415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679] object



---------------------------------------------------------------------------

OverflowError                             Traceback (most recent call last)

<ipython-input-5-0da0a4edd8c4> in <module>
     35 nppi2 = np.array(piar2)
     36 print("np.array(101桁整数) = ",nppi2,nppi2.dtype)
---> 37 nppi_i32 = np.array(piar2,dtype=np.int32)
     38 print("nppi_i32 = ",nppi_i32,nppi_i32.dtype)


OverflowError: Python int too large to convert to C long
import numpy as np
import math
def int_info(dt):
    dt_max = np.iinfo(dt).max
    a = math.log10(dt_max)
    print(dt,"max値 = ",dt_max,"(",int(a),"桁)")

int_info(np.int)
int_info(np.int8)
int_info(np.int16)
int_info(np.int32)
int_info(np.int64)
int_info(np.uint8)
int_info(np.uint16)
int_info(np.uint32)
int_info(np.uint64)
<class 'int'> max値 =  2147483647 ( 9 桁)
<class 'numpy.int8'> max値 =  127 ( 2 桁)
<class 'numpy.int16'> max値 =  32767 ( 4 桁)
<class 'numpy.int32'> max値 =  2147483647 ( 9 桁)
<class 'numpy.int64'> max値 =  9223372036854775807 ( 18 桁)
<class 'numpy.uint8'> max値 =  255 ( 2 桁)
<class 'numpy.uint16'> max値 =  65535 ( 4 桁)
<class 'numpy.uint32'> max値 =  4294967295 ( 9 桁)
<class 'numpy.uint64'> max値 =  18446744073709551615 ( 19 桁)

パイソンに桁数は無いという話はあったが、整数の話であったか。小数点は、15桁まで表示している
対して、Numpyは、float64がpythonより少ない8桁何か変。float32は、7桁。float64float32で1桁の差しかないのはおかしい。float16int化はお約束ということで
Numpyの整数は、dtype=Noneの場合はなんかもう数値じゃなくオブジェクトとして扱っているし。int32はErrorなのね。有効桁数しらべたけどそんな感じなのね

と思ったが!調べていくと

import numpy as np
pi_str = "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679"
pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
pi2 = 31415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
print("python π(文字列)    = ",pi_str)

print("=== Python(Myマシン) float ===")
print("python π(有効桁)    = ", pi)
print("python π            = ","%.100f" % pi)
piar = [pi]
print("python array(有効桁) = ", piar[0])
print("python array         = ","%.100f" % piar[0])

print("=== Numpy float(Myマシン) ===")
nppi = np.empty((1))
nppi[0] = pi
nppi_f64 = np.empty((1),dtype=np.float64)
nppi_f64[0] = pi
nppi_f32 = np.empty((1),dtype=np.float32)
nppi_f32[0] = pi
nppi_f16 = np.empty((1),dtype=np.float16)
nppi_f16[0] = pi

print("str    π            = ",pi_str)
print("flot   π            = ", nppi[0])
print("flot   π(100桁表示) = ","%.100f" % nppi[0])
print("flot64 π            = ", nppi_f64[0])
print("flot64 π(100桁表示) = ","%.100f" % nppi_f64[0])
print("flot32 π            = ",nppi_f32[0])
print("flot32 π(100桁表示) = ","%.100f" % nppi_f32[0])
print("flot16 π      = ",nppi_f16[0])
print("flot16 π(100桁表示) = ","%.100f" % nppi_f16[0])
python π(文字列)    =  3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
=== Python(Myマシン) float ===
python π(有効桁)    =  3.141592653589793
python π            =  3.1415926535897931159979634685441851615905761718750000000000000000000000000000000000000000000000000000
python array(有効桁) =  3.141592653589793
python array         =  3.1415926535897931159979634685441851615905761718750000000000000000000000000000000000000000000000000000
=== Numpy float(Myマシン) ===
str    π            =  3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
flot   π            =  3.141592653589793
flot   π(100桁表示) =  3.1415926535897931159979634685441851615905761718750000000000000000000000000000000000000000000000000000
flot64 π            =  3.141592653589793
flot64 π(100桁表示) =  3.1415926535897931159979634685441851615905761718750000000000000000000000000000000000000000000000000000
flot32 π            =  3.1415927
flot32 π(100桁表示) =  3.1415927410125732421875000000000000000000000000000000000000000000000000000000000000000000000000000000
flot16 π      =  3.14
flot16 π(100桁表示) =  3.1406250000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

print表記の切り上げだったみたいです。pythonのデータ型とNumpyのデータ型ではprint表記の有効桁数が違うみたいでその影響みたいです
float64表現では、pythonとnumpyで同じ桁数のデータを保存していることがわかりました。