17. 整数、浮動小数点数、複素数
#17. 整数、浮動小数点、および複素数
Python の数値オブジェクトは、特殊な実装を備えた通常のオブジェクトです。これらは、リスト、辞書、関数、クラス、モジュールと同じオブジェクト モデルに参加します。各値には、オブジェクト ヘッダー、型ポインター、参照カウント動作、および操作用の型スロットがあります。
主な組み込み数値型は次のとおりです。
| タイプ | Python 名 | 主な表現 |
|---|---|---|
| 整数 | int |
任意精度の整数 |
| ブール値 | bool |
のシングルトンサブクラスint |
| 浮動小数点 | float |
Cダブル |
| 複雑な | complex |
C ダブルスのペア |
これらの型は Python レベルでは単純に見えますが、それぞれに実行時の重要なトレードオフがあります。
17.1 数値オブジェクトはオブジェクトである
Python 整数は、通常、生の CPU 整数として Python 変数に格納されません。python x = 42 CPython レベルでは、xPython 整数オブジェクトを指します。
概念的には:text x ---> PyLongObject object header integer payload 浮動小数点数と複素数についても同様です。python a = 1.5 b = 1 + 2j 概念的には:```text
a ---> PyFloatObject
object header
double value
b ---> PyComplexObject
object header
double real
double imag
オブジェクト モデルは、通常の Python の動作を数値化します。python
print(type(42))
print((42).class)
print((42).bit_length())
## 17.2 整数オブジェクト
パイソン`int`は任意の精度です。```python
x = 10 ** 100
print(x)
```値は 32 ビットまたは 64 ビットではオーバーフローしません。 CPython は必要に応じて内部表現を拡張します。
Cレベルタイプは一般的に呼ばれます`PyLongObject`。
概念的には:```text
PyLongObject
PyVarObject header
ob_size
digit array
```の`ob_size`フィールドは内部桁数と符号の両方をエンコードします。数字配列には、絶対値が大きな基数で格納されます。
これが、Python が以下を計算できる理由です。```python
x = 2 ** 1000
y = x * x
print(y)
```整数オーバーフローなし。
その代償として、大きな整数はマシン整数よりも多くのメモリとより多くの CPU 時間を必要とします。
## 17.3 整数桁のストレージ
CPython は整数を複数の内部数字として保存します。
簡略化したモデル:```text
value = sign * (d0 + d1 * base + d2 * base^2 + ...)
```小さな整数の場合は、1 桁だけが必要な場合があります。
大きな整数の場合は、多くの桁が必要になります。
概念的には:```text
42
sign = positive
digits = [42]
2**1000
sign = positive
digits = [d0, d1, d2, ...]
```この表現は、人間が 10 進数を数字として記述する方法に似ていますが、CPython では効率性を高めるためにはるかに大きな内部基数が使用されます。
算術演算はこれらの数字配列に対して行われます。```text
small int addition
cheap
large int addition
cost grows with number of digits
large int multiplication
cost grows more quickly, with specialized algorithms for large cases
```## 17.4 整数符号
記号は、別個の Python オブジェクトとしてではなく、サイズ メタデータを通じて表されます。
概念的には:```text
ob_size > 0
positive integer
ob_size == 0
zero
ob_size < 0
negative integer
```数字配列には大きさが格納されます。
例:```text
123
ob_size = positive digit count
digits = magnitude
-123
ob_size = negative digit count
digits = magnitude
```この表現により、オブジェクトがコンパクトに保たれます。
## 17.5 整数の不変性
整数は不変です。```python
x = 10
x += 1
```これは整数オブジェクトを変更しません`10`。別の整数オブジェクトを作成または取得し、再バインドします`x`。
概念的には:```text
x ---> int object 10
x += 1
x ---> int object 11
```この動作は、オブジェクトが共有されている場合に発生します。```python
a = 10
b = a
a += 1
print(a) # 11
print(b) # 10
bは依然として元の整数オブジェクトを参照します。
17.6 小さい整数の再利用
CPython はいくつかの小さな整数オブジェクトを再利用します。```python a = 1 b = 1
これは最適化です。これにより、共通の値の割り当てが削減されます。
整数値の比較では同一性に依存しないでください。
正しい:```python
if x == 1:
...
```正しくない:```python
if x is 1:
...
isオブジェクトのアイデンティティをテストします。==数値の等価性をテストします。
17.7 ブールオブジェクトboolのサブクラスですint。```python
print(isinstance(True, int)) # True
print(True + True) # 2
正確に 2 つのブール値シングルトン オブジェクトがあります。python
True
False
型の関係は次のとおりです。text
bool
subclass of int
これは歴史的および実用的な互換性のために存在します。ブール値は数値コンテキストで機能しますが、コードでは真理値としてブール値を使用する必要があります。python
if ready:
...
それよりも:python
if ready == True:
...
C レベルでは、拡張コードは通常、次のようなブール値を返します。c
Py_RETURN_TRUE;
Py_RETURN_FALSE;
## 17.8 真理値テスト
数値オブジェクトは真理値テストに参加します。```python
bool(0) # False
bool(1) # True
bool(-1) # True
bool(0.0) # False
bool(0j) # False
```数値型のルールは単純です。```text
zero value
false
nonzero value
true
```真実のテストにはタイププロトコル機構が使用されます。 C レベルでは、数値型はブール変換などのスロットを通じて動作を提供します。
## 17.9 整数演算
一般的な整数演算には次のものがあります。```python
a + b
a - b
a * b
a // b
a % b
a ** b
a << n
a >> n
a & b
a | b
a ^ b
~a
```これらは数値スロットにマップされます。
概念的には:```text
PyLong_Type
nb_add
nb_subtract
nb_multiply
nb_floor_divide
nb_remainder
nb_power
nb_lshift
nb_rshift
nb_and
nb_or
nb_xor
nb_invert
```各操作は Python オブジェクトを受け取り、Python オブジェクトを返します。
結果が機械語に収まる場合でも、結果は Python オブジェクトになります。
## 17.10 整数の除算
Python には 2 つの主要な除算演算子があります。```python
a / b # true division
a // b # floor division
```整数の場合:```python
print(5 / 2) # 2.5
print(5 // 2) # 2
/通常の整数の場合は浮動小数点数を返します。//床の結果を返します。
負の値の場合:python print(-5 // 2) # -3 print(-5 % 2) # 1 アイデンティティは次のとおりです。text a == (a // b) * b + (a % b) と%Python セマンティクスで必要な符号規則を保持します。
17.11 ビット演算
整数は、無限の符号拡張を備えた 2 の補数で表されるかのようにビット演算をサポートします。python x & y x | y x ^ y ~x x << n x >> n 例:python print(5 & 3) # 1 print(5 | 3) # 7 print(5 ^ 3) # 6 print(~5) # -6 の結果~x以下に続きます:```text
~x == -x - 1
## 17.12 整数メソッド
整数メソッドは、内部値の有用なプロパティを公開します。```python
x = 1024
print(x.bit_length())
print(x.bit_count())
bit_length絶対値を表すのに必要なビット数を返します。```python
print((0).bit_length()) # 0
print((1).bit_length()) # 1
print((2).bit_length()) # 2
print((3).bit_length()) # 2
`bit_count`絶対値の人口数を返します。```python
print((7).bit_count()) # 3
```これらのメソッドは、多くの場合、内部数値演算や CPU 組み込み関数 (利用可能な場合) に効率的にマッピングされます。
## 17.13 整数からバイトへの変換
整数はバイト シーケンスとの間で変換できます。```python
x = 1024
data = x.to_bytes(2, byteorder="big")
print(data)
again = int.from_bytes(data, byteorder="big")
print(again)
```これは以下にとって重要です。```text
binary protocols
cryptography
file formats
network byte order
serialization
```エンディアンは明示的に指定する必要があります。```python
x.to_bytes(4, "big")
x.to_bytes(4, "little")
```同じ整数でも、バイト順序に応じて異なるバイト レイアウトが生成されます。
## 17.14 浮動小数点オブジェクト
パイソン`float`通常、C double のラッパーです。
概念的には:```text
PyFloatObject
PyObject header
double value
```float オブジェクトは固定サイズです。```python
x = 1.5
y = 2.25
print(x + y)
```浮動小数点演算は、数値スロットとプラットフォーム浮動小数点演算を通じて実装されます。
キーポイント: float は近似 2 進浮動小数点数です。
## 17.15 バイナリ浮動小数点
小数部は 2 進数で正確に表現できないことがよくあります。```python
print(0.1 + 0.2)
```これは通常、次のように出力されます。```text
0.30000000000000004
```問題は表現力だ。`0.1`同様に、有限のバイナリ展開はありません。`1/3`有限小数展開はありません。
したがって、格納される値は、最も近い表現可能なバイナリ浮動小数点数です。
これは平等性に影響します。```python
print(0.1 + 0.2 == 0.3) # False
```概算の数値作業には公差ベースの比較を使用します。```python
import math
math.isclose(0.1 + 0.2, 0.3)
```## 17.16 浮動小数点数の特殊な値
浮動小数点数には特別な値が含まれます。```python
inf = float("inf")
nan = float("nan")
neg_inf = float("-inf")
```Infinity は、多くの比較で期待どおりに動作します。```python
print(inf > 1e308) # True
```NaN は異常です:```python
nan = float("nan")
print(nan == nan) # False
print(nan != nan) # True
```NaN は「数値ではない」という意味です。それ自体と同等ではありません。
この動作は、通常のオブジェクト ID ロジックではなく、浮動小数点ルールに従います。
## 17.17 Float ハッシュと等価性
数値型は等価性とハッシュ化を調整します。```python
print(1 == 1.0) # True
print(hash(1) == hash(1.0))
```2 つの数値オブジェクトが等しい場合、それらのハッシュは同じでなければなりません。
これにより、辞書が正しく動作できるようになります。```python
d = {}
d[1] = "int"
d[1.0] = "float"
print(d)
```2 番目の割り当ては同じキー位置を更新します。`1 == 1.0`。
このタイプ間の数値の等価性は便利ですが、タイプの異なるキーを期待しているユーザーを驚かせる可能性があります。
## 17.18 浮動小数点変換
変換:```python
float(1)
int(1.9)
round(1.9)
intゼロに向かって切り捨てる:```python
print(int(1.9)) # 1
print(int(-1.9)) # -1
`round`Python の丸め規則に従います。```python
print(round(2.5))
print(round(3.5))
```浮動小数点から整数への変換では、浮動小数点が意図した値を正確に表していない場合、情報が失われる可能性があります。
10 進の金融算術演算の場合は、次を使用します。`decimal.Decimal`バイナリ浮動小数点ではなく。
## 17.19 複雑なオブジェクト
パイソン`complex`2 つの浮動小数点値を格納します。```text
PyComplexObject
PyObject header
double real
double imag
```例:```python
z = 3 + 4j
print(z.real)
print(z.imag)
```実数部と虚数部は浮動小数点です。
複素数は算術演算をサポートします。```python
a = 1 + 2j
b = 3 + 4j
print(a + b)
print(a * b)
```注文はサポートされていません:```python
(1 + 2j) < (3 + 4j) # TypeError
```Python の数値モデルには、複素数に対する自然な全順序付けはありません。
## 17.20 複素数演算
複素乗算は次のようになります。```text
(a + bi)(c + di) = (ac - bd) + (ad + bc)i
```Python はこれを複合型の実装内で処理します。
例:```python
a = 1 + 2j
b = 3 + 4j
print(a * b) # (-5+10j)
```分割と権力もサポートされています。
高度な数値処理の場合、`cmath`モジュールは、複雑さを認識する数学関数を提供します。```python
import cmath
print(cmath.sqrt(-1))
```## 17.21 数値タワー
Python の数値モデルには概念的な階層があります。```text
numbers.Number
numbers.Complex
numbers.Real
numbers.Rational
numbers.Integral
```組み込み型はおおよそ次のように適合します。
|タイプ |概念的な役割 |
| --------- | ----------------------------- |
|`complex`|複雑な |
|`float`|リアル |
|`int`|インテグラル |
|`bool`|実際の整数サブクラス |
の`numbers`モジュールは、数値プロトコルの抽象基本クラスを提供します。
ほとんどの通常の CPython 操作では、抽象基本クラスのディスパッチではなく具象型スロットが使用されますが、階層は期待される動作を定義するのに役立ちます。
## 17.22 混合数値演算
混合数値演算は強制ルールとディスパッチルールに従います。```python
print(1 + 2.5) # 3.5
print(1 + 2j) # (1+2j)
print(1.5 + 2j) # (3.5+2j)
```一般的な拡幅方向:```text
int -> float -> complex
```これは概念的なモデルです。実際の実装では、オペランド型間のバイナリ演算ディスパッチを使用します。
ユーザー定義の数値クラスの場合、戻り値`NotImplemented`他のオペランドで反映された動作を試行させます。```python
class N:
def __add__(self, other):
return NotImplemented
```##17.23`__index__`
`__index__`これは、オブジェクトがインデックス付けとスライスのために正確な整数として解釈できることを意味します。```python
class Index:
def __index__(self):
return 2
xs = [10, 20, 30, 40]
print(xs[Index()])
```これはより厳しいです`__int__`。
ユースケースには次のようなものがあります。```text
list indexes
slice bounds
range arguments
bit operations
low-level integer contexts
```C レベルでは、これは整数インデックス プロトコルの動作に対応します。
##17.24`__int__`、`__float__`、 そして`__complex__`変換メソッドを使用すると、カスタムの数値のようなオブジェクトを組み込みの数値型に変換できます。```python
class Value:
def __int__(self):
return 10
def __float__(self):
return 10.5
def __complex__(self):
return 10.5 + 2j
```使用法:```python
v = Value()
print(int(v))
print(float(v))
print(complex(v))
```これらの変換により、組み込みの数値オブジェクトが作成されます。
カスタム タイプが自動的に完全な数値になるわけではありません。算術メソッドは依然として個別に実装する必要があります。
## 17.25 数値スロット
数値の動作はスロットを通じて実装されます。
概念的なスロット テーブル:```text
PyNumberMethods
nb_add
nb_subtract
nb_multiply
nb_remainder
nb_divmod
nb_power
nb_negative
nb_positive
nb_absolute
nb_bool
nb_invert
nb_lshift
nb_rshift
nb_and
nb_xor
nb_or
nb_int
nb_float
nb_index
nb_matrix_multiply
nb_inplace_add
...
```Python 構文はこの表にマップされます。
|構文 |スロットのコンセプト |
| ---------- | --------------------- |
|`a + b`|追加 |
|`a - b`|引き算 |
|`a * b`|乗算 |
|`a @ b`|行列の乗算 |
|`-a`|否定 |
|`abs(a)`|絶対値 |
|`bool(a)`|真理値 |
|`int(a)`|整数変換 |
|`float(a)`|浮動小数点変換 |
|`a << b`|左シフト |
このスロット テーブルが、組み込みおよび拡張数値型を Python 構文と統合できる理由です。
## 17.26 インプレースの数値演算
インプレース演算子には次のものがあります。```python
x += y
x -= y
x *= y
x //= y
x **= y
```不変の数値の場合、インプレース操作により新しいオブジェクトが作成され、名前が再バインドされます。```python
x = 10
before = id(x)
x += 1
after = id(x)
print(before == after) # usually False
```変更可能な数値のようなオブジェクトの場合、型は真のインプレース変更を実装できます。
内蔵`int`、`float`、 そして`complex`は不変です。
## 17.27 小数と分数
標準ライブラリは、コア組み込みの外部に数値型を提供します。`decimal.Decimal`10 進浮動小数点演算を提供します。```python
from decimal import Decimal
print(Decimal("0.1") + Decimal("0.2"))
fractions.Fraction有理演算を提供します。```python
from fractions import Fraction
print(Fraction(1, 3) + Fraction(1, 6))
セマンティクスが問題に一致する場合に使用します。
|必要 |タイプ |
| ----------------------------------- | ---------- |
|一般的な整数 |`int`|
|おおよその科学的数値計算 |`float`|
|複雑な算術 |`complex`|
| 10 進の金融算術 |`Decimal`|
|正確な有理算術 |`Fraction`|
## 17.28 C API: 数値の作成
整数の作成:```c
PyObject *x = PyLong_FromLong(42);
if (x == NULL) {
return NULL;
}
```より幅広い C 型から作成:```c
PyObject *x = PyLong_FromLongLong(value);
```フロートの作成:```c
PyObject *f = PyFloat_FromDouble(3.14);
if (f == NULL) {
return NULL;
}
```複合体の作成:```c
PyObject *z = PyComplex_FromDoubles(1.0, 2.0);
if (z == NULL) {
return NULL;
}
```それぞれが新しい参照を返します。呼び出し元がそれを所有します。
## 17.29 C API: 数値の抽出
C ロングを抽出する:```c
long value = PyLong_AsLong(obj);
if (value == -1 && PyErr_Occurred()) {
return NULL;
}
```エラーチェックは重要です。`-1`有効な結果になる可能性があります。
double の抽出:```c
double value = PyFloat_AsDouble(obj);
if (value == -1.0 && PyErr_Occurred()) {
return NULL;
}
```再度、例外状態を確認してください。
整数のようなコンテキストの場合、正確な整数のセマンティクスが必要な場合は、インデックス変換 API を使用します。
## 17.30 C 境界でのオーバーフロー
Python の整数は任意の精度です。 C の整数は固定幅です。
この変換は失敗する可能性があります。```c
long value = PyLong_AsLong(obj);
```もし`obj`C には大きすぎます`long`。
Python レベルの例:```python
x = 10 ** 100
```この値は Python として有効です`int`、ただし、C の整数型には適合しない可能性があります。
C 拡張コードはオーバーフロー エラーを処理する必要があります。
よくある間違いは、Python を想定していることです`int`いつもはまる`int`、`long`、 または`size_t`。
## 17.31 パフォーマンスノート
数値のパフォーマンスは表現に依存します。
小さな整数の演算は最適化されていますが、引き続き Python オブジェクト上で動作します。
緊密なループ:```python
total = 0
for i in range(10_000_000):
total += i
```多くの Python レベルの操作を実行します。```text
load total
load i
integer addition
create or retrieve result integer
store total
loop control
```これは、生のマシン整数に対する同等の C よりもはるかに遅いです。
大きな数値配列の場合は、生の値をコンパクトに格納する特殊なライブラリを使用します。`array`、`memoryview`、または NumPy。
Python の組み込み数値型は、密な数値ベクトル計算ではなく、スカラー セマンティクスを最適化します。
## 17.32 記憶メモ
整数のリストには、整数オブジェクトへの参照が格納されます。```python
xs = [1, 2, 3, 4]
```概念的には:```text
list
[ptr][ptr][ptr][ptr]
| | | |
v v v v
int int int int
```配列には生の値が格納されます。```python
from array import array
xs = array("i", [1, 2, 3, 4])
```概念的には:```text
array
[int][int][int][int]
```これが、大規模で同種の数値データに対して配列の方がメモリ効率が高い理由です。
## 17.33 よくある数値の落とし穴
|落とし穴 |例 |より良いアプローチ |
| -------------------------------------- | ------------------------------- | ------------------------- |
|使用する`is`数字の場合 |`x is 1000` | `x == 1000`|
| float から 10 進数の正確性を期待します |`0.1 + 0.2 == 0.3` | `math.isclose`または`Decimal`|
|永続的`hash()` | `hash(x)`安定した ID として |`hashlib`|
| Python int が C long に適合すると仮定します。`PyLong_AsLong`チェックされていない |オーバーフローをチェックする |
|密な数値配列にリストを使用する |`[0] * n`巨大な数値データの場合 |`array`または NumPy |
| NaN を通常に比較する |`nan == nan`|使用`math.isnan`|
|整数増加コストを無視する |ホットパスの巨大な力 |アルゴリズムの境界を考慮する |
## 17.34 メンタルモデル
このモデルを使用します。```text
int
immutable arbitrary-precision integer
variable-size digit array
no fixed overflow
cost grows with magnitude
bool
singleton subclass of int
truth-value type
values are True and False
float
immutable wrapper around C double
approximate binary floating-point
supports inf and nan
complex
immutable pair of doubles
real and imaginary parts
arithmetic supported
ordering unsupported
```CPython レベルでは次のようになります。```text
numeric operation
dispatch through type slots
operate on concrete numeric representation
allocate or return result object
manage references
```## 17.35 概要
CPython は、特殊な C レイアウトを使用して、整数、浮動小数点、および複素数を Python オブジェクトとして実装します。`int`は任意精度のストレージを使用するため、固定幅のオーバーフローは回避されますが、値のサイズに応じて増大するコストが発生します。`float`C の double をラップし、バイナリ浮動小数点の動作を継承します。`complex`2 つの double を格納し、複雑な算術演算をサポートします。
これらの数値型は不変です。操作はオペランドを変更するのではなく、結果オブジェクトを作成します。これらの動作は、数値スロット、変換プロトコル、ハッシュ ルール、および C API 関数を通じて統合されています。