2017-01-17 7 views
4

numpyアレイで.sum()を使って落とし穴を見つけたようですが、説明が見つかりません。本質的には、大きな配列を合計しようとすると無意味な解答が始まりますが、は暗黙のうちにとなり、私は出力を十分に理解することができません。例えばnumpy.sum()大きな配列で奇妙な結果が出る

、これは期待どおりに動作します:

の両方に同じ出力を与える
a = sum(xrange(2000)) 
print('a is {}'.format(a)) 

b = np.arange(2000).sum() 
print('b is {}'.format(b)) 

a is 1999000 
b is 1999000 

しかし、これは動作しません:

c = sum(xrange(200000)) 
print('c is {}'.format(c)) 

d = np.arange(200000).sum() 
print('d is {}'.format(d)) 

を与えます次の出力:

c is 19999900000 
d is -1474936480 

さらに大きな配列では、肯定的な結果を得ることができます。珍しいことが全く起こっていないことを特定できないので、これはもっと狡猾です。たとえば、この:

e = sum(xrange(100000000)) 
print('e is {}'.format(e)) 

f = np.arange(100000000).sum() 
print('f is {}'.format(f)) 

はこれを与える:

e is 4999999950000000 
f is 887459712 

私はが、これはデータ型と関係していたし、実際にもパイソンfloatを使用して問題を解決するために思われることを推測:

e = sum(xrange(100000000)) 
print('e is {}'.format(e)) 

f = np.arange(100000000, dtype=float).sum() 
print('f is {}'.format(f)) 

寄付:

e is 4999999950000000 
f is 4.99999995e+15 

私はCompで背景がありません。 Sci。自分が立ち往生しているのを見つけました(おそらくこれは詐欺です)。私が試したこと:

  1. numpyアレイのサイズは固定です。いいえ。 thisが最初にMemoryErrorを打つべきであると思われるようです。
  2. 私は何とか32ビットインストールをしている可能性があります(おそらく関連性がありません)。いいえ、私はthisに続き、私が64ビットを持っていることを確認しました。
  3. 奇妙なその他の例sum動作;いいえ()私はthisを見つけましたが、それがどのように当てはまるのか分かりません。

誰かが私が紛失していることを簡単に説明し、私が何を読みたいのか教えてもらえますか?また、毎回dtypeを定義することを覚えておく以外にも、これをやめたり、警告を出す方法はありますか?

おそらく関連:Pythonの2.7にEnthoughtキャノピーの不足

のWindows 7

numpy 1.11.3

。9

+1

をnumpy'整数がC型整数に依存している、おそらく 'ので、 Pythonは無制限の整数範囲を持っています。浮きは浮きます。彼らは非常に高くなる可能性があります。 –

+1

'np.arange(5).dtype'を確認してください。おそらく、64ビットの代わりに32ビットの整数を使用しています。また、同じPythonインストールでこれらのチェックをすべて実行していることを確認してください。 – user2357112

+0

ある種のオーバーフローのように見えます...整数の符号も上書きされているようですが、これは時には否定的な結果を得る理由かもしれません。 – keksnicoh

答えて

5

Windowsでは(64ビットシステムでも)NumPyのデフォルトの整数は、Pythonから変換する場合intsが32ビットです。 LinuxとMacでは64ビットです。

64ビット整数を指定して、それが動作します:

d = np.arange(200000, dtype=np.int64).sum() 
print('d is {}'.format(d)) 

出力:

c is 19999900000 
d is 19999900000 

最もエレガントではありませんが、あなたには、いくつかのmonkey patchingを行うことができ、functools.partialを使用して:

from functools import partial 

np.arange = partial(np.arange, dtype=np.int64) 

今すぐnp.arangeは、デフォルトで64ビット整数で動作します。

+1

が表示されています。これは私には意味がありますが、私の重要な質問の1つは、これをフラグする方法があるかどうかでした。デバッグ時に私のレーダーの下にこれが落ち込むのは非常に簡単です。私はこれを逃したことを識別する方法はありますか? – roganjosh

+0

可能な解決策を追加しました。 –

3

私はnumpyの専門家ではないんだけど、純粋なPythonであなたのarange(200000)結果を再現することができます。つまり

>>> s = 0 
>>> for i in range(200000): 
...  s += i 
...  s &= 0xffffffff 
>>> s 
2820030816 
>>> s.bit_length() 
32 
>>> s - 2**32 # adjust for that "the sign bit" is set 
-1474936480 

、あなたが見ている結果がnumpyは上の算術演算を行っている場合、私は何を期待され符号付き2の補数32ビット整数。

私はnumpyのエキスパートではないので、私は決して驚くことのない良いアプローチを提案することはできません(私はこれをコメントとして残していましたが、うまくフォーマットされたコードを表示できませんでした)。

+1

「2の補数」を検索します。さまざまな固定ビット幅(8,16,32,64)では、事実上すべてのコンピュータハードウェアが符号付き整数を表すための方式です。 'C'(CPythonとnumpyがコード化されている)のような低レベルの言語では、そのようなネイティブのハードウェアタイプがあなたのものです。無限に広い2の補数整数のPythonの錯覚を実装するには、カバーの下でたくさんのコードが必要です。 –

+0

多くのおかげで、私は今それを読んでいます。この "ケースの下にあるたくさんのコード"は、私をたくさんのことから守ってくれました:)この場合、Wimは彼の答えで 'numpy'のオープンチケットにリンクしています。この特定のケース(これは私を投げ捨てたものです)にオーバーフローエラーがないことが認識されていますが、今何年も開いています:( – roganjosh

3

これは明らかにnumpyの32ビットオーバーフロー整数型です。通常はnp.seterrを使用してこのような状況で失敗するnumpyのを設定することができます:あなたがここに運の外にあるかもしれないので

>>> import numpy as np 
>>> np.seterr(over='raise') 
{'divide': 'warn', 'invalid': 'warn', 'over': 'warn', 'under': 'ignore'} 
>>> np.int8(127) + np.int8(2) 
FloatingPointError: overflow encountered in byte_scalars 

しかし、sumは明示的、行動「エラーがオーバーフローに提起されていない」と記載されています。 numpyを使うのは、便宜上、パフォーマンスのトレードオフです。

ただし、手動でこのように、アキュムレータのためのDTYPEを指定することができます。これは、未解決の問題であり、それはいつかnumpyの開発者によって修正される可能性があるため、

>>> a = np.ones(129) 
>>> a.sum(dtype=np.int8) # will overflow 
-127 
>>> a.sum(dtype=np.int64) # no overflow 
129 

ウォッチチケット#593

+0

チケットを含めていただきありがとうございます。 Windowsが自動的にintを32ビットに変換することを知らないことと組み合わせて、混乱してしまった。 – roganjosh

2

Numpyのデフォルトの整数型は、C long型と同じです。現在、これは64ビットプラットフォームでは64ビットであるとは保証されていません。実際、Windowsではlongです。常に 32ビットです。

その結果、numpyの合計が値をオーバーフローし、折り返します。

残念ながら、私が知る限り、はありません。dtypeを変更する方法はです。毎回np.int64と指定する必要があります。

def arange(*args, **kw): 
    return np.arange(dtype=np.int64, *args, **kw) 

をして、numpyの年代の代わりにそのバージョンを使用します。

あなたはarange独自に作成しようとすることができます。

EDIT:あなたはフラグにこのをしたい場合、あなたは自分のコードの先頭にこのようなものを入れることができます:

assert np.array(0).dtype.name != 'int32', 'This needs to be run with 64-bit integers!'