andyvand / gmpy

Automatically exported from code.google.com/p/gmpy
GNU Lesser General Public License v3.0
0 stars 0 forks source link

`1` and `True` yield different result for extended slicing #39

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?

    >>> a = gmpy2.xmpz(0b1000)
    >>> b = a.copy()
    >>> c = a.copy()
    >>> a[1::2] = 1
    >>> b[1::2] = True
    >>> c[1::2] = gmpy2.xmpz(0b11)
    >>> a == b
    False
    >>> a == c
    False
    >>> map(bin, [a, b, c])
    ['0b10', '0b1010', '0b1010']

What is the expected output?

    >>> a = numpy.array([0,0,0,1],dtype=numpy.bool)
    >>> b = a.copy()
    >>> c = a.copy()
    >>> a[1::2] = 1
    >>> b[1::2] = True
    >>> c[1::2] = [1,1]
    >>> all(a == b and all(a == c)
    True
    >>> to_bin = lambda arr: ''.join("01"[d] for d in arr[::-1])
    >>> map(to_bin, [a, b, c])
    ['1010', '1010', '1010']

Or

    >>> a = [0,0,0,1]
    >>> b = a[:]
    >>> c = a[:]
    >>> a[1::2] = 1
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: must assign iterable to extended slice
    >>> b[1::2] = True
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: must assign iterable to extended slice
    >>> c[1::2] = [1,1]
    >>> to_bin(c)
    '1010'

What version of the product are you using? On what operating system?

r312

Please provide any additional information below.

Original issue reported on code.google.com by 4kir4...@gmail.com on 2 Jun 2010 at 11:47

GoogleCodeExporter commented 9 years ago
The same issue leads to confusing error message for simple slice assignment:

    >>> d = gmpy2.xmpz(0b1000)
    >>> d[1:3] = gmpy2.xmpz(0b111)
    >>> bin(d)
    '0b1110'
    >>> d[1:3] = [True,True]
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: must specify sequence of bits

Expected 
>>> d = numpy.array([0,0,0,1], dtype=bool)
>>> d[1:3] = [1,1,1]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: shape mismatch: objects cannot be broadcast to a single shape
>>> d[1:3] = [True,True]
>>> to_bin(d)
'1110'

Or

>>> d = [0,0,0,1]
>>> d[1:3] = [1,1,1]
>>> to_bin(d)
'11110'
>>> d = [0,0,0,1]
>>> d[1:3] = [1,1]
>>> to_bin(d)
'1110'

Original comment by `4kir4...@gmail.com` on 2 Jun 2010 at 11:49
GoogleCodeExporter commented 9 years ago
My use of True is an ugly hack. When getting bits from a number, GMP treats 0 
as an 
infinitely long number with all bits set to 0. This makes assigning a slice of 
bits 
to 0 very easy. Unfortunately, 1 is considered an infinitely long number with 
the 
first bit set to 1 and all remaining bits set to 0. From GMP's perspective, -1 
is an 
infinitely strong number with all bits set to 1. I'll remove the special 
handling of 
True. Then the sample code will need to use -1 (not intuitive either) or I need 
to 
introduce a bit_mask(n) function to return a number with n bits set. This would 
probably be more useful anyway.

I haven't thought about supporting assignment from a list. Since I'm assigning 
to 
bit positions of a number, I thought it was reasonable that the bit positions 
came 
from another number.

The alternative is to only support setting a slice to either all 0 or all 1.

I'm open to suggestions.

Thanks for the feedback.

Original comment by casevh on 2 Jun 2010 at 1:44

GoogleCodeExporter commented 9 years ago
I changed slice assignments to only accept 0 or 1. It's not as flexible but 
also not
as confusing. I think this is reasonable since gmpy2 isn't intended for bit 
operations. 

Original comment by casevh on 4 Jun 2010 at 4:43

GoogleCodeExporter commented 9 years ago
Changed to allow getting and setting arbitrary sequences of bits. True and 
False are no longer treated as special values. To provide an as-long-as-needed 
source of 0 bits, use the value 0. To provide an as-long-as-needed source of 1 
bits, use ~0 (or -1). This matches the behavior of GMP and of 2's complement 
integers.

If you want to use a list of boolean values as input, see the new method pack():

>>> gmpy2.pack([True, False, True],1)
mpz(5)

Original comment by casevh on 12 Aug 2010 at 5:42