<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Wed, Nov 12, 2014 at 11:10 PM, Sebastian <span dir="ltr"><<a href="mailto:sebix@sebix.at" target="_blank">sebix@sebix.at</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">On 2014-11-04 19:44, Charles R Harris wrote:<br>
> On Tue, Nov 4, 2014 at 11:19 AM, Sebastian <<a href="mailto:sebix@sebix.at">sebix@sebix.at</a>> wrote:<br>
><br>
>> On 2014-11-04 15:06, Todd wrote:<br>
>>> On Tue, Nov 4, 2014 at 2:50 PM, Sebastian Wagner <<a href="mailto:sebix@sebix.at">sebix@sebix.at</a><br>
>><br>
>>> <mailto:<a href="mailto:sebix@sebix.at">sebix@sebix.at</a>>> wrote:<br>
>>><br>
>>> Hello,<br>
>>><br>
>>> I want to bring up Issue #2522 'numpy.diff fails on unsigned<br>
>> integers<br>
>>> (Trac #1929)' [1], as it was resonsible for an error in one<br>
>> of our<br>
>>> programs. Short explanation of the bug: np.diff performs a<br>
>> subtraction<br>
>>> on the input array. If this is of type uint and the data<br>
>> contains<br>
>>> falling data, it results in an artihmetic underflow.<br>
>>><br>
>>> >>> np.diff(np.array([0,1,0], dtype=np.uint8))<br>
>>> array([ 1, 255], dtype=uint8)<br>
>>><br>
>>> @charris proposed either<br>
>>> - a note to the doc string and maybe an example to clarify<br>
>> things<br>
>>> - or raise a warning<br>
>>> but with a discussion on the list.<br>
>>><br>
>>> I would like to start it now, as it is an error which is not<br>
>> easily<br>
>>> detectable (no errors or warnings are thrown). In our case<br>
>> the<br>
>>> type of a<br>
>>> data sequence, with only zeros and ones, had type f8 as also<br>
>> every<br>
>>> other<br>
>>> one, has been changed to u4. As the programs looked for<br>
>> values ==1 and<br>
>>> ==-1, it broke silently.<br>
>>> In my opinion, a note in the docs is not enough and does not<br>
>> help<br>
>>> if the<br>
>>> type changed or set after the program has been written.<br>
>>> I'd go for automatic upcasting of uints by default and an<br>
>> option<br>
>>> to turn<br>
>>> it off, if this behavior is explicitly wanted. This wouldn't<br>
>> be<br>
>>> correct<br>
>>> from the point of view of a programmer, but as most of the<br>
>> users<br>
>>> have a<br>
>>> scientific background who excpect it 'to work', instead of<br>
>> sth is<br>
>>> theoretically correct but not convenient. (I count myself to<br>
>> the first<br>
>>> group)<br>
>>><br>
>>><br>
>>><br>
>>> When you say "automatic upcasting", that would be, for example<br>
>> uint8<br>
>>> to int16? What about for uint64? There is no int128.<br>
>> The upcast should go to the next bigger, otherwise it would again<br>
>> result<br>
>> in wrong values. uint64 we can't do that, so it has to stay.<br>
>>> Also, when you say "by default", is this only when an overflow is<br>
>>> detected, or always?<br>
>> I don't know how I could detect an overflow in the diff-function.<br>
>> In<br>
>> subtraction it should be possible, but that's very deep in the<br>
>> numpy-internals.<br>
>>> How would the option to turn it off be implemented? An argument<br>
>> to<br>
>>> np.diff or some sort of global option?<br>
>> I thought of a parameter upcast_int=True for the function.<br>
><br>
> Could check for non-decreasing sequence in the unsigned case. Note<br>
> that differences of signed integers can also overflow. One way to<br>
> check in general is to determine the expected sign using comparisons.<br>
<br>
I think you mean a decreasing/non-increasing instead of non-decreasing<br>
sequence?<br>
It's also the same check as checking for a sorted sequence. But I<br>
currently don't know how I could do that efficiently without np.diff in<br>
Python, in Cython it should be easily possible.<br></blockquote><div><br></div><div>For a 1D array, you could simply do:</div><div><br></div><div><font face="monospace">    if a.dtype.kind == 'u' and np.any(a[1:] < a[:-1]):</font></div><div><font face="monospace">        # warn, upcast, or whatever</font></div><div><span style="font-family:monospace">    return a[1:] - a[:-1]</span><br></div><div><br></div><div>The general case is a little more complicated because of the axis handling, but if you look at the source <a href="https://github.com/numpy/numpy/blob/v1.9.1/numpy/lib/function_base.py#L1055">https://github.com/numpy/numpy/blob/v1.9.1/numpy/lib/function_base.py#L1055</a>, you just need to replace 1: with slice1 and :-1 with slice2.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
np.gradient has the same problem:<br>
>>> np.random.seed(89)<br>
>>> d = np.random.randint(0,2,size=10).astype(np.uint8); d<br>
array([1, 0, 0, 1, 0, 1, 1, 0, 0, 0], dtype=uint8)<br>
>>> np.diff(d)<br>
array([255,   0,   1, 255,   1,   0, 255,   0,   0], dtype=uint8)<br>
>>> np.gradient(d)<br>
array([ 255. ,  127.5,    0.5,    0. ,    0. ,    0.5,  127.5,  127.5,<br>
          0. ,    0. ])<br></blockquote><div><br></div><div>The case of gradient is kind of sad, because it actually goes through the trouble of figuring out the right dtype for the output if yt isn't floating point already, but doesn't upcast the operations... Take a look at the source here, <a href="https://github.com/numpy/numpy/blob/v1.9.1/numpy/lib/function_base.py#L886">https://github.com/numpy/numpy/blob/v1.9.1/numpy/lib/function_base.py#L886</a>, and wherever you find something like </div><div><br></div><div><span style="color:rgb(51,51,51);font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:12px;line-height:16.7999992370605px;white-space:pre">    out[slice1] </span><span class="" style="color:rgb(110,84,148);font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:12px;line-height:16.7999992370605px;white-space:pre">=</span><span style="color:rgb(51,51,51);font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:12px;line-height:16.7999992370605px;white-space:pre"> (y[slice2] </span><span class="" style="color:rgb(110,84,148);font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:12px;line-height:16.7999992370605px;white-space:pre">-</span><span style="color:rgb(51,51,51);font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:12px;line-height:16.7999992370605px;white-space:pre"> y[slice3])</span><br></div><div><br></div><div>simply replace it with:</div><div><br></div><div><span style="color:rgb(51,51,51);font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:12px;line-height:16.7999992370605px;white-space:pre">    np.subtract(</span><span style="color:rgb(51,51,51);font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:12px;line-height:16.7999992370605px;white-space:pre">y[slice2], </span><span style="color:rgb(51,51,51);font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:12px;line-height:16.7999992370605px;white-space:pre">y[slice3], dtype=dtype, out=</span><span style="color:rgb(51,51,51);font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:12px;line-height:16.7999992370605px;white-space:pre">out[slice1]</span><span style="color:rgb(51,51,51);font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:12px;line-height:16.7999992370605px;white-space:pre">)</span></div><div><br></div><div>and it should work fine.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
---<br>
gpg --keyserver <a href="http://keys.gnupg.net" target="_blank">keys.gnupg.net</a> --recv-key DC9B463B<br>
_______________________________________________<br>
NumPy-Discussion mailing list<br>
<a href="mailto:NumPy-Discussion@scipy.org">NumPy-Discussion@scipy.org</a><br>
<a href="http://mail.scipy.org/mailman/listinfo/numpy-discussion" target="_blank">http://mail.scipy.org/mailman/listinfo/numpy-discussion</a><br>
</blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature">(\__/)<br>( O.o)<br>( > <) Este es Conejo. Copia a Conejo en tu firma y ayúdale en sus planes de dominación mundial.</div>
</div></div>