1. ホーム
  2. python

[解決済み] なぜnumpyでは負の累乗にできないのですか?

2022-02-08 15:43:16

質問

リーマンシータ関数をモデリングしています。

import numpy as np
def theta(s, n=100):
    a_range = np.arange(2, n + 1)
    return 1 + sum(1/(a_range ** s))

負の値では動作しません。 s 例えば theta(-2) はこのエラーを導きます。

      1 def theta(s, n=100):
      2     a_range = np.arange(1)
----> 3     return 1 + sum(1/(a_range ** s))
      4 
      5 theta(-2)

      ValueError: Integers to negative integer powers are not allowed.

どうして? x^-1 は、単に 1/x 私の計算が正しければ

解答方法は?

NumPyでは、以下のような操作の出力d型を選択するためのロジックが使用されています。 a_range ** s は値ではなく、dtypes に基づいています。つまり a_range ** -2 と同じ出力d型を持たなければなりません。 a_range ** 2 .

のようなものが重要です。 numpy.array([2]) ** 2 は整数の出力を与えるので、つまり numpy.array([2]) ** -2 は整数を与えるか、何も与えないかのどちらかでなければなりません。整数を負の整数乗にすることはNumPyのエラーであるため、彼らは何もしないことを選択した。

浮動小数点出力が必要なら、浮動小数点入力を作ってください。

a_range = np.arange(2, n + 1, dtype=float)

または

a_range = np.arange(2, n + 1).astype(float)


NumPyの型規則は、上記の説明からは想像できないような奇妙な点がいくつかあります。一つは、スカラーと配列の両方を含む操作では、スカラーのdtypeが は、実際には "降格"されるかもしれません。 入力のdtypesが結果のdtypesを選ぶのに使われる前に、その値に基づいて。

>>> (numpy.array([1], dtype='int8') + numpy.int32(1)).dtype
dtype('int8')
>>> (numpy.array([1], dtype='int8') + numpy.array([1], dtype='int32')).dtype
dtype('int32')

ここでは、スカラー numpy.int32(1) は int8 に demoted" されますが、配列は demoted されません。(実際には、int8への降格よりももう少し複雑で、特に符号付き/符号なしの処理についてです。 実装 をご覧ください)。

第二に、uint64が関係するとき、NumPyは突然負の指数で大丈夫なように見えるかもしれません。

>>> numpy.arange(5, dtype='uint64') ** -2
__main__:1: RuntimeWarning: divide by zero encountered in power
array([       inf, 1.        , 0.25      , 0.11111111, 0.0625    ])

これは、NumPyがuint64の値と負の値の両方に対応する十分な大きさの整数のd型を見つけることができず、あきらめて入力をfloatに強制しているためです。スカラー型の "demotion"を避ける限り、符号付きd型の正の指数でも同じように見ることができます。

>>> numpy.arange(5, dtype='uint64') ** numpy.array([2], dtype='int32')
array([ 0.,  1.,  4.,  9., 16.])