Skip to content

Commit 7bfe0c8

Browse files
antonwolfyvtavana
andauthored
Add dpnp.binary_repr function (#2168)
* Implement dpnp.binary_repr * Add third party tests * Update links and add more examples with dpnp.binary_repr * Apply suggestions from code review Co-authored-by: Vahid Tavanashad <[email protected]> --------- Co-authored-by: Vahid Tavanashad <[email protected]>
1 parent d536dae commit 7bfe0c8

File tree

3 files changed

+203
-3
lines changed

3 files changed

+203
-3
lines changed

dpnp/dpnp_iface_bitwise.py

Lines changed: 133 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,12 @@
4141

4242

4343
import dpctl.tensor._tensor_elementwise_impl as ti
44+
import numpy
4445

4546
from dpnp.dpnp_algo.dpnp_elementwise_common import DPNPBinaryFunc, DPNPUnaryFunc
4647

4748
__all__ = [
49+
"binary_repr",
4850
"bitwise_and",
4951
"bitwise_invert",
5052
"bitwise_left_shift",
@@ -58,6 +60,71 @@
5860
]
5961

6062

63+
def binary_repr(num, width=None):
64+
"""
65+
Return the binary representation of the input number as a string.
66+
67+
For negative numbers, if `width` is not given, a minus sign is added to the
68+
front. If `width` is given, the two's complement of the number is returned,
69+
with respect to that width.
70+
71+
In a two's-complement system negative numbers are represented by the two's
72+
complement of the absolute value. A N-bit two's-complement system can
73+
represent every integer in the range :math:`-2^{N-1}` to :math:`+2^{N-1}-1`.
74+
75+
For full documentation refer to :obj:`numpy.binary_repr`.
76+
77+
Parameters
78+
----------
79+
num : int
80+
Only an integer decimal number can be used.
81+
width : {None, int}, optional
82+
The length of the returned string if `num` is positive, or the length
83+
of the two's complement if `num` is negative, provided that `width` is
84+
at least a sufficient number of bits for `num` to be represented in the
85+
designated form. If the `width` value is insufficient, an error is
86+
raised.
87+
Default: ``None``.
88+
89+
Returns
90+
-------
91+
bin : str
92+
Binary representation of `num` or two's complement of `num`.
93+
94+
See Also
95+
--------
96+
:obj:`dpnp.base_repr` : Return a string representation of a number in the
97+
given base system.
98+
bin : Python's built-in binary representation generator of an integer.
99+
100+
Notes
101+
-----
102+
:obj:`dpnp.binary_repr` is equivalent to using :obj:`dpnp.base_repr` with
103+
base 2, but significantly faster.
104+
105+
Examples
106+
--------
107+
>>> import numpy as np
108+
>>> np.binary_repr(3)
109+
'11'
110+
>>> np.binary_repr(-3)
111+
'-11'
112+
>>> np.binary_repr(3, width=4)
113+
'0011'
114+
115+
The two's complement is returned when the input number is negative and
116+
`width` is specified:
117+
118+
>>> np.binary_repr(-3, width=3)
119+
'101'
120+
>>> np.binary_repr(-3, width=5)
121+
'11101'
122+
123+
"""
124+
125+
return numpy.binary_repr(num, width)
126+
127+
61128
_BITWISE_AND_DOCSTRING = """
62129
Computes the bitwise AND of the underlying binary representation of each
63130
element `x1_i` of the input array `x1` with the respective element `x2_i`
@@ -98,14 +165,16 @@
98165
:obj:`dpnp.logical_and` : Compute the truth value of ``x1`` AND ``x2`` element-wise.
99166
:obj:`dpnp.bitwise_or`: Compute the bit-wise OR of two arrays element-wise.
100167
:obj:`dpnp.bitwise_xor` : Compute the bit-wise XOR of two arrays element-wise.
168+
:obj:`dpnp.binary_repr` : Return the binary representation of the input number
169+
as a string.
101170
102171
Examples
103172
--------
104173
>>> import dpnp as np
105174
>>> x1 = np.array([2, 5, 255])
106-
>>> x2 = np.array([3,14,16])
175+
>>> x2 = np.array([3, 14, 16])
107176
>>> np.bitwise_and(x1, x2)
108-
[2, 4, 16]
177+
array([ 2, 4, 16])
109178
110179
>>> a = np.array([True, True])
111180
>>> b = np.array([False, True])
@@ -117,6 +186,19 @@
117186
118187
>>> x1 & x2
119188
array([ 2, 4, 16])
189+
190+
The number 13 is represented by ``00001101``. Likewise, 17 is represented by
191+
``00010001``. The bit-wise AND of 13 and 17 is therefore ``000000001``, or 1:
192+
193+
>>> np.bitwise_and(np.array(13), 17)
194+
array(1)
195+
196+
>>> np.bitwise_and(np.array(14), 13)
197+
array(12)
198+
>>> np.binary_repr(12)
199+
'1100'
200+
>>> np.bitwise_and(np.array([14, 3]), 13)
201+
array([12, 1])
120202
"""
121203

122204
bitwise_and = DPNPBinaryFunc(
@@ -167,6 +249,8 @@
167249
:obj:`dpnp.logical_or` : Compute the truth value of ``x1`` OR ``x2`` element-wise.
168250
:obj:`dpnp.bitwise_and`: Compute the bit-wise AND of two arrays element-wise.
169251
:obj:`dpnp.bitwise_xor` : Compute the bit-wise XOR of two arrays element-wise.
252+
:obj:`dpnp.binary_repr` : Return the binary representation of the input number
253+
as a string.
170254
171255
Examples
172256
--------
@@ -181,6 +265,15 @@
181265
182266
>>> x1 | x2
183267
array([ 6, 5, 255])
268+
269+
The number 13 has the binary representation ``00001101``. Likewise, 16 is
270+
represented by ``00010000``. The bit-wise OR of 13 and 16 is then ``00011101``,
271+
or 29:
272+
273+
>>> np.bitwise_or(np.array(13), 16)
274+
array(29)
275+
>>> np.binary_repr(29)
276+
'11101'
184277
"""
185278

186279
bitwise_or = DPNPBinaryFunc(
@@ -231,6 +324,8 @@
231324
:obj:`dpnp.logical_xor` : Compute the truth value of ``x1`` XOR `x2`, element-wise.
232325
:obj:`dpnp.bitwise_and`: Compute the bit-wise AND of two arrays element-wise.
233326
:obj:`dpnp.bitwise_or` : Compute the bit-wise OR of two arrays element-wise.
327+
:obj:`dpnp.binary_repr` : Return the binary representation of the input number
328+
as a string.
234329
235330
Examples
236331
--------
@@ -250,6 +345,14 @@
250345
251346
>>> a ^ b
252347
array([ True, False])
348+
349+
The number 13 is represented by ``00001101``. Likewise, 17 is represented by
350+
``00010001``. The bit-wise XOR of 13 and 17 is therefore ``00011100``, or 28:
351+
352+
>>> np.bitwise_xor(np.array(13), 17)
353+
array(28)
354+
>>> np.binary_repr(28)
355+
'11100'
253356
"""
254357

255358
bitwise_xor = DPNPBinaryFunc(
@@ -298,13 +401,21 @@
298401
:obj:`dpnp.bitwise_or` : Compute the bit-wise OR of two arrays element-wise.
299402
:obj:`dpnp.bitwise_xor` : Compute the bit-wise XOR of two arrays element-wise.
300403
:obj:`dpnp.logical_not` : Compute the truth value of NOT x element-wise.
404+
:obj:`dpnp.binary_repr` : Return the binary representation of the input number
405+
as a string.
301406
302407
Examples
303408
--------
304409
>>> import dpnp as np
410+
411+
The number 13 is represented by ``00001101``. The invert or bit-wise NOT of 13
412+
is then:
413+
305414
>>> x = np.array([13])
306415
>>> np.invert(x)
307-
-14
416+
array([-14])
417+
>>> np.binary_repr(-14, width=8)
418+
'11110010'
308419
309420
>>> a = np.array([True, False])
310421
>>> np.invert(a)
@@ -315,6 +426,7 @@
315426
316427
>>> ~a
317428
array([False, True])
429+
318430
"""
319431

320432
invert = DPNPUnaryFunc(
@@ -368,6 +480,8 @@
368480
See Also
369481
--------
370482
:obj:`dpnp.right_shift` : Shift the bits of an integer to the right.
483+
:obj:`dpnp.binary_repr` : Return the binary representation of the input number
484+
as a string.
371485
372486
Examples
373487
--------
@@ -382,6 +496,13 @@
382496
383497
>>> x1 << x2
384498
array([10, 20, 40])
499+
500+
>>> np.binary_repr(5)
501+
'101'
502+
>>> np.left_shift(np.array(5), 2)
503+
array(20)
504+
>>> np.binary_repr(20)
505+
'10100'
385506
"""
386507

387508
left_shift = DPNPBinaryFunc(
@@ -434,6 +555,8 @@
434555
See Also
435556
--------
436557
:obj:`dpnp.left_shift` : Shift the bits of an integer to the left.
558+
:obj:`dpnp.binary_repr` : Return the binary representation of the input number
559+
as a string.
437560
438561
Examples
439562
--------
@@ -448,6 +571,13 @@
448571
449572
>>> x1 >> x2
450573
array([5, 2, 1])
574+
575+
>>> np.binary_repr(10)
576+
'1010'
577+
>>> np.right_shift(np.array(10), 1)
578+
array(5)
579+
>>> np.binary_repr(5)
580+
'101'
451581
"""
452582

453583
right_shift = DPNPBinaryFunc(

tests/third_party/cupy/io_tests/__init__.py

Whitespace-only changes.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import pytest
2+
3+
from tests.third_party.cupy import testing
4+
5+
6+
class TestBinaryRepr(testing.NumpyAliasBasicTestBase):
7+
8+
func = "binary_repr"
9+
10+
11+
@testing.parameterize(
12+
*testing.product(
13+
{
14+
"args": [
15+
(0,),
16+
(3,),
17+
(-3,),
18+
(0, 0),
19+
(3, 5),
20+
(-3, 5),
21+
# TODO(unno): Insuffisicent width is deprecated in numpy>=1.13.
22+
# We need to check if it cause a warning, and maybe it causes an
23+
# error in the future.
24+
# (3, 0),
25+
# (-3, 0),
26+
]
27+
}
28+
)
29+
)
30+
class TestBinaryReprValues(testing.NumpyAliasValuesTestBase):
31+
32+
func = "binary_repr"
33+
34+
35+
@pytest.mark.skip("base_repr() is not implemented")
36+
class TestBaseRepr(testing.NumpyAliasBasicTestBase):
37+
38+
func = "base_repr"
39+
40+
41+
@testing.parameterize(
42+
*testing.product(
43+
{
44+
"args": [
45+
(0,),
46+
(5,),
47+
(-5,),
48+
(0, 2),
49+
(0, 10),
50+
(0, 36),
51+
(5, 2),
52+
(5, 10),
53+
(5, 36),
54+
(-5, 2),
55+
(-5, 10),
56+
(-5, 36),
57+
(-5, 2, 0),
58+
(-5, 2, 2),
59+
(-5, 2, 10),
60+
(5, 2, 0),
61+
(5, 2, 2),
62+
(5, 2, 10),
63+
]
64+
}
65+
)
66+
)
67+
@pytest.mark.skip("base_repr() is not implemented")
68+
class TestBaseReprValues(testing.NumpyAliasValuesTestBase):
69+
70+
func = "base_repr"

0 commit comments

Comments
 (0)