19日に更新してた

アフィリエイトはないよ

numpy.power は2の31乗とか10の10乗とかの大きい計算をするときには、引数のどちらかを float にしておかないと合わなくなるみたい

win10 home上の jupyter notebook で*1何故か計算が合わないので、printdebug していたら、numpy.power がどうも合わない*2

import math
import numpy as np

for i in range(1,16):
    print(f"{i:>2} {pow(10,i):>20} {math.pow(10,i):>20} {np.power(10,i):>20}")

 1                   10                 10.0                   10
 2                  100                100.0                  100
 3                 1000               1000.0                 1000
 4                10000              10000.0                10000
 5               100000             100000.0               100000
 6              1000000            1000000.0              1000000
 7             10000000           10000000.0             10000000
 8            100000000          100000000.0            100000000
 9           1000000000         1000000000.0           1000000000
10          10000000000        10000000000.0           1410065408
11         100000000000       100000000000.0           1215752192
12        1000000000000      1000000000000.0           -727379968
13       10000000000000     10000000000000.0           1316134912
14      100000000000000    100000000000000.0            276447232
15     1000000000000000   1000000000000000.0          -1530494976

なので、どうも numpy のようです。

ちなみに

np.__version__

'1.21.2'

import sys
sys.version

'3.7.11 (default, Jul 27 2021, 09:42:29) [MSC v.1916 64 bit (AMD64)]'


ついでに、

for i in range(33):
    print(f"{i:>2} {pow(2,i):>15} {np.power(2,i):>15}")

 0               1               1
 1               2               2
 2               4               4
 3               8               8
 4              16              16
 5              32              32
 6              64              64
 7             128             128
 8             256             256
 9             512             512
10            1024            1024
11            2048            2048
12            4096            4096
13            8192            8192
14           16384           16384
15           32768           32768
16           65536           65536
17          131072          131072
18          262144          262144
19          524288          524288
20         1048576         1048576
21         2097152         2097152
22         4194304         4194304
23         8388608         8388608
24        16777216        16777216
25        33554432        33554432
26        67108864        67108864
27       134217728       134217728
28       268435456       268435456
29       536870912       536870912
30      1073741824      1073741824
31      2147483648     -2147483648
32      4294967296               0

になりますです。

少しいじって、引数のどちらかをfloat にして

for i in range(34):
    print(f"{i:>4} {np.power(10.0,i):>25} {np.power(10,float(i)):>25} {np.power(10,1.0*i):>25} {np.power(10,i):>25}")

計算すると、

  0                       1.0                       1.0                       1.0                         1
   1                      10.0                      10.0                      10.0                        10
   2                     100.0                     100.0                     100.0                       100
   3                    1000.0                    1000.0                    1000.0                      1000
   4                   10000.0                   10000.0                   10000.0                     10000
   5                  100000.0                  100000.0                  100000.0                    100000
   6                 1000000.0                 1000000.0                 1000000.0                   1000000
   7                10000000.0                10000000.0                10000000.0                  10000000
   8               100000000.0               100000000.0               100000000.0                 100000000
   9              1000000000.0              1000000000.0              1000000000.0                1000000000
  10             10000000000.0             10000000000.0             10000000000.0                1410065408
  11            100000000000.0            100000000000.0            100000000000.0                1215752192
  12           1000000000000.0           1000000000000.0           1000000000000.0                -727379968
  13          10000000000000.0          10000000000000.0          10000000000000.0                1316134912
  14         100000000000000.0         100000000000000.0         100000000000000.0                 276447232
  15        1000000000000000.0        1000000000000000.0        1000000000000000.0               -1530494976
  16                     1e+16                     1e+16                     1e+16                1874919424
  17                     1e+17                     1e+17                     1e+17                1569325056
  18                     1e+18                     1e+18                     1e+18               -1486618624
  19                     1e+19                     1e+19                     1e+19               -1981284352
  20                     1e+20                     1e+20                     1e+20                1661992960
  21                     1e+21                     1e+21                     1e+21                -559939584
  22                     1e+22                     1e+22                     1e+22               -1304428544
  23    1.0000000000000001e+23    1.0000000000000001e+23    1.0000000000000001e+23                -159383552
  24                     1e+24                     1e+24                     1e+24               -1593835520
  25                     1e+25                     1e+25                     1e+25                1241513984
  26                     1e+26                     1e+26                     1e+26                -469762048
  27                     1e+27                     1e+27                     1e+27                -402653184
  28                     1e+28                     1e+28                     1e+28                 268435456
  29                     1e+29                     1e+29                     1e+29               -1610612736
  30                     1e+30                     1e+30                     1e+30                1073741824
  31                     1e+31                     1e+31                     1e+31               -2147483648
  32                     1e+32                     1e+32                     1e+32                         0
  33                     1e+33                     1e+33                     1e+33                         0

と合うようになりました。

ついでに、

for i in range(33):
    print(f"{i:>4} {np.power(2.0,i):>20} {np.power(2,float(i)):>20} {np.power(2,i*1.0):>20} {np.power(2,i):>20}")

も、

   0                  1.0                  1.0                  1.0                    1
   1                  2.0                  2.0                  2.0                    2
   2                  4.0                  4.0                  4.0                    4
   3                  8.0                  8.0                  8.0                    8
   4                 16.0                 16.0                 16.0                   16
   5                 32.0                 32.0                 32.0                   32
   6                 64.0                 64.0                 64.0                   64
   7                128.0                128.0                128.0                  128
   8                256.0                256.0                256.0                  256
   9                512.0                512.0                512.0                  512
  10               1024.0               1024.0               1024.0                 1024
  11               2048.0               2048.0               2048.0                 2048
  12               4096.0               4096.0               4096.0                 4096
  13               8192.0               8192.0               8192.0                 8192
  14              16384.0              16384.0              16384.0                16384
  15              32768.0              32768.0              32768.0                32768
  16              65536.0              65536.0              65536.0                65536
  17             131072.0             131072.0             131072.0               131072
  18             262144.0             262144.0             262144.0               262144
  19             524288.0             524288.0             524288.0               524288
  20            1048576.0            1048576.0            1048576.0              1048576
  21            2097152.0            2097152.0            2097152.0              2097152
  22            4194304.0            4194304.0            4194304.0              4194304
  23            8388608.0            8388608.0            8388608.0              8388608
  24           16777216.0           16777216.0           16777216.0             16777216
  25           33554432.0           33554432.0           33554432.0             33554432
  26           67108864.0           67108864.0           67108864.0             67108864
  27          134217728.0          134217728.0          134217728.0            134217728
  28          268435456.0          268435456.0          268435456.0            268435456
  29          536870912.0          536870912.0          536870912.0            536870912
  30         1073741824.0         1073741824.0         1073741824.0           1073741824
  31         2147483648.0         2147483648.0         2147483648.0          -2147483648
  32         4294967296.0         4294967296.0         4294967296.0                    0

答えが合う模様です。numpy.arangeでも step を1.0にしないと range と同じでした。

wsl上の python3 でも試してみたのですが、合わない計算結果同士は合わないけれども wsl上でも numpy の模様。対処法も一緒。

import numpy as np
for i in range(25):
	print(f"{i:>2} {np.power(10.0,i):>30} {np.power(10,i):>30}")

import sys
print(sys.version)
print(np.__version__)
 0                            1.0                              1
 1                           10.0                             10
 2                          100.0                            100
 3                         1000.0                           1000
 4                        10000.0                          10000
 5                       100000.0                         100000
 6                      1000000.0                        1000000
 7                     10000000.0                       10000000
 8                    100000000.0                      100000000
 9                   1000000000.0                     1000000000
10                  10000000000.0                    10000000000
11                 100000000000.0                   100000000000
12                1000000000000.0                  1000000000000
13               10000000000000.0                 10000000000000
14              100000000000000.0                100000000000000
15             1000000000000000.0               1000000000000000
16                          1e+16              10000000000000000
17                          1e+17             100000000000000000
18                          1e+18            1000000000000000000
19                          1e+19           -8446744073709551616
20                          1e+20            7766279631452241920
21                          1e+21            3875820019684212736
22                          1e+22            1864712049423024128
23                          1e+23             200376420520689664
24                          1e+24            2003764205206896640
3.6.9 (default, Jan 26 2021, 15:33:00)
[GCC 8.4.0]
1.13.3

wsl 上で2の n 乗の合わないさわりの部分だけ計算すると、

for i in range(66):
	if np.power(2,i)!=pow(2,i):
		print(i,np.power(2,i))

63 -9223372036854775808
64 0
65 0

こんな感じ。

wsl からもどって windows prompt 上でも jupyternotebook 上でも

import numpy as np
print(np.power(2,30)*2)

を実行すると、

RuntimeWarning: overflow encountered in int_scalars
print(np.power(2,30)*2)
-2147483648

となるので、まぁそういうことらしい。

問題のあるところは僕にはわからないけれど、遊んでみるには非常に面白かった。

とりあえず、きちんと動かす方法はわかっているので一段落?

*1:windows prompt から python.exe でも同じ結果になる。 version は記事中。

*2:84の5乗になぜマイナスが付く?