Skip to content

Commit 1afb3b9

Browse files
committed
gh-146151: support for complex arrays in the array module
1 parent 52c0186 commit 1afb3b9

File tree

5 files changed

+280
-20
lines changed

5 files changed

+280
-20
lines changed

Doc/library/array.rst

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
--------------
1010

1111
This module defines an object type which can compactly represent an array of
12-
basic values: characters, integers, floating-point numbers. Arrays are mutable :term:`sequence`
12+
basic values: characters, integers, floating-point numbers, complex numbers. Arrays are mutable :term:`sequence`
1313
types and behave very much like lists, except that the type of objects stored in
1414
them is constrained. The type is specified at object creation time by using a
1515
:dfn:`type code`, which is a single character. The following type codes are
@@ -46,6 +46,11 @@ defined:
4646
+-----------+--------------------+-------------------+-----------------------+-------+
4747
| ``'d'`` | double | float | 8 | |
4848
+-----------+--------------------+-------------------+-----------------------+-------+
49+
| ``'F'`` | float complex | complex | 8 | \(3) |
50+
+-----------+--------------------+-------------------+-----------------------+-------+
51+
| ``'D'`` | double complex | complex | 16 | \(3) |
52+
+-----------+--------------------+-------------------+-----------------------+-------+
53+
4954

5055
Notes:
5156

@@ -63,6 +68,15 @@ Notes:
6368
(2)
6469
.. versionadded:: 3.13
6570

71+
(3)
72+
Complex types (``F`` and ``D``) are available unconditionally,
73+
regardless on support for complex types (the Annex G of the C11 standard)
74+
by the C compiler.
75+
As specified in the C11 standard, each complex type is represented by a
76+
two-element C array containing, respectively, the real and imaginary parts.
77+
78+
.. versionadded:: 3.15
79+
6680

6781
The actual representation of values is determined by the machine architecture
6882
(strictly speaking, by the C implementation). The actual size can be accessed
@@ -139,9 +153,10 @@ The module defines the following type:
139153
.. method:: byteswap()
140154

141155
"Byteswap" all items of the array. This is only supported for values which are
142-
1, 2, 4, or 8 bytes in size; for other types of values, :exc:`RuntimeError` is
156+
1, 2, 4, 8 or 16 bytes in size; for other types of values, :exc:`RuntimeError` is
143157
raised. It is useful when reading data from a file written on a machine with a
144-
different byte order.
158+
different byte order. Note, that for complex types the order of
159+
components (the real part, followed by imaginary part) is preserved.
145160

146161

147162
.. method:: count(x)

Doc/whatsnew/3.15.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,15 @@ argparse
629629
(Contributed by Savannah Ostrowski in :gh:`142390`.)
630630

631631

632+
array
633+
-----
634+
635+
* Support the :c:expr:`float complex` and :c:expr:`double complex` C types in
636+
the :mod:`array` module (formatting characters ``'F'`` and ``'D'``
637+
respectively).
638+
(Contributed by Sergey B Kirpichev in :gh:`146151`.)
639+
640+
632641
base64
633642
------
634643

Lib/test/test_array.py

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class ArraySubclassWithKwargs(array.array):
3131
def __init__(self, typecode, newarg=None):
3232
array.array.__init__(self)
3333

34-
typecodes = 'uwbBhHiIlLfdqQ'
34+
typecodes = 'uwbBhHiIlLfdqQFD'
3535

3636
class MiscTest(unittest.TestCase):
3737

@@ -113,6 +113,10 @@ def __index__(self):
113113
UTF16_BE = 19
114114
UTF32_LE = 20
115115
UTF32_BE = 21
116+
IEEE_754_FLOAT_COMPLEX_LE = 22
117+
IEEE_754_FLOAT_COMPLEX_BE = 23
118+
IEEE_754_DOUBLE_COMPLEX_LE = 24
119+
IEEE_754_DOUBLE_COMPLEX_BE = 25
116120

117121

118122
class ArrayReconstructorTest(unittest.TestCase):
@@ -139,7 +143,7 @@ def test_error(self):
139143
self.assertRaises(ValueError, array_reconstructor,
140144
array.array, "b", UNKNOWN_FORMAT, b"")
141145
self.assertRaises(ValueError, array_reconstructor,
142-
array.array, "b", 22, b"")
146+
array.array, "b", 26, b"")
143147
self.assertRaises(ValueError, array_reconstructor,
144148
array.array, "d", 16, b"a")
145149

@@ -279,7 +283,7 @@ def test_byteswap(self):
279283
example = self.example
280284
a = array.array(self.typecode, example)
281285
self.assertRaises(TypeError, a.byteswap, 42)
282-
if a.itemsize in (1, 2, 4, 8):
286+
if a.itemsize in (1, 2, 4, 8, 16):
283287
b = array.array(self.typecode, example)
284288
b.byteswap()
285289
if a.itemsize==1:
@@ -1525,6 +1529,55 @@ def test_byteswap(self):
15251529
b.byteswap()
15261530
self.assertEqual(a, b)
15271531

1532+
class CFPTest(NumberTest):
1533+
example = [-42j, 0, 42+1j, 1e5j, -1e10]
1534+
outside = 23
1535+
1536+
def assertEntryEqual(self, entry1, entry2):
1537+
self.assertAlmostEqual(entry1, entry2)
1538+
1539+
def test_cmp(self):
1540+
a = array.array(self.typecode, self.example)
1541+
self.assertIs(a == 42, False)
1542+
self.assertIs(a != 42, True)
1543+
1544+
self.assertIs(a == a, True)
1545+
self.assertIs(a != a, False)
1546+
self.assertIs(a < a, False)
1547+
self.assertIs(a <= a, True)
1548+
self.assertIs(a > a, False)
1549+
self.assertIs(a >= a, True)
1550+
1551+
self.assertIs(a == 2*a, False)
1552+
self.assertIs(a != 2*a, True)
1553+
self.assertIs(a < 2*a, True)
1554+
self.assertIs(a <= 2*a, True)
1555+
self.assertIs(a > 2*a, False)
1556+
self.assertIs(a >= 2*a, False)
1557+
1558+
def test_nan(self):
1559+
a = array.array(self.typecode, [float('nan')])
1560+
b = array.array(self.typecode, [float('nan')])
1561+
self.assertIs(a != b, True)
1562+
self.assertIs(a == b, False)
1563+
1564+
def test_byteswap(self):
1565+
a = array.array(self.typecode, self.example)
1566+
self.assertRaises(TypeError, a.byteswap, 42)
1567+
if a.itemsize in (1, 2, 4, 8):
1568+
b = array.array(self.typecode, self.example)
1569+
b.byteswap()
1570+
if a.itemsize==1:
1571+
self.assertEqual(a, b)
1572+
else:
1573+
# On alphas treating the byte swapped bit patterns as
1574+
# floats/doubles results in floating-point exceptions
1575+
# => compare the 8bit string values instead
1576+
self.assertNotEqual(a.tobytes(), b.tobytes())
1577+
b.byteswap()
1578+
self.assertEqual(a, b)
1579+
1580+
15281581
class FloatTest(FPTest, unittest.TestCase):
15291582
typecode = 'f'
15301583
minitemsize = 4
@@ -1551,6 +1604,15 @@ def test_alloc_overflow(self):
15511604
self.fail("Array of size > maxsize created - MemoryError expected")
15521605

15531606

1607+
class ComplexFloatTest(CFPTest, unittest.TestCase):
1608+
typecode = 'F'
1609+
minitemsize = 8
1610+
1611+
class ComplexDoubleTest(CFPTest, unittest.TestCase):
1612+
typecode = 'D'
1613+
minitemsize = 16
1614+
1615+
15541616
class LargeArrayTest(unittest.TestCase):
15551617
typecode = 'b'
15561618

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Support the :c:expr:`float complex` and :c:expr:`double complex` C types in
2+
the :mod:`array` module (formatting characters ``'F'`` and ``'D'``
3+
respectively). Patch by Sergey B Kirpichev.

0 commit comments

Comments
 (0)