#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 関数を通じて統合されています。