Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BUG: Fix binary_repr for negative numbers #7178

Merged
merged 1 commit into from
Mar 13, 2016
Merged

BUG: Fix binary_repr for negative numbers #7178

merged 1 commit into from
Mar 13, 2016

Conversation

gfyoung
Copy link
Contributor

@gfyoung gfyoung commented Feb 3, 2016

Addresses issue in #7168 in which passing in negative numbers with insufficient width parameters resulted in completely incorrect two's complement representations (e.g. all zero's) or even an error. Now, it will return the two's complement with width equal to the minimum number of bits needed to represent the complement.

@gfyoung
Copy link
Contributor Author

gfyoung commented Feb 3, 2016

As noted in my commit message, using Python's built-in bin function provides a nice speed up to what is already a pretty high-performing function:

python -m timeit -n 10000 -s "import numpy as np" "np.binary_repr(123456789987654321)"

On master : 4.07 usec per loop
On PR : 2.99 usec per loop

python -m timeit -n 10000 -s "import numpy as np" "np.binary_repr(-123456789987654321)"

On master : 4.19 usec per loop
On PR : 1.85 usec per loop

python -m timeit -n 10000 -s "import numpy as np" "np.binary_repr(10, width=60)"

On master : 2.33 usec per loop
On PR : 2.12 usec per loop

python -m timeit -n 10000 -s "import numpy as np" "np.binary_repr(-123456789, width=5)"

On master : KeyError
On PR : 3.09 usec per loop

@gfyoung
Copy link
Contributor Author

gfyoung commented Feb 17, 2016

@charris : if there are no issues, can this be merged now since #7194 was merged in? Or can someone else take a look at this?

@ahaldane
Copy link
Member

If it is not possible to represent the number given the supplied width, would it be better to just raise an exception? Silently returning a value with a width different from what was requested seems dangerous.

@gfyoung
Copy link
Contributor Author

gfyoung commented Feb 17, 2016

It's for backwards compatibility reasons. That's what is done with positive numbers, so the behavior should be consistent with negative numbers.

@ahaldane
Copy link
Member

I see.

But I still feel it's dangerous, and the positive case could be considered a bug. There are no unit tests for it. Maybe we should take this opportunity to break backward compatibility, and raise an exception in that case? base_repr doesn't have this problem, by the way.

Can anyone more experienced on backward compatibility problems comment?

@gfyoung
Copy link
Contributor Author

gfyoung commented Feb 17, 2016

Well, I would beg to differ in terms of the testing. If you look at the test suite, I explicitly wrote one for insufficient widths to make sure I got the behavior I coded it to do. However, I can understand why you might be "surprised" if you suddenly got a representation with a width larger than you had requested. TBH I don't quite understand why the function was written as it was previously, so another person's input would be great as well!

@ahaldane
Copy link
Member

Oh, I meant there were no existing tests for extending the width past the user's request, meaning it may be unintentional. I do see you added some though :)

@gfyoung
Copy link
Contributor Author

gfyoung commented Feb 29, 2016

Does anyone have anything to add to this? At this point, I'm still leaning towards maintaining backwards compatibility, but other opinions are welcome!

@seberg
Copy link
Member

seberg commented Mar 5, 2016

I have to admit I have a slight preference for just erroring out if the width is not enough to represent the twos complement for negative numbers. Unless that is a backwards incompatible break?

@gfyoung
Copy link
Contributor Author

gfyoung commented Mar 6, 2016

@seberg : There would be a backwards compatibility break because that behavior is used for positive numbers, so for consistency, it should be used for negative numbers as well.

@seberg
Copy link
Member

seberg commented Mar 6, 2016

Hmmmm, good point. On the other hand, the user suddenly has to know whether his number was positive or negative to make sense of the result. Unrelated, I think we could mention bin in the doc string. Since the usefulness of this function was probably partially when bin did not exist.

@gfyoung
Copy link
Contributor Author

gfyoung commented Mar 6, 2016

  1. Given that the binary representation (without knowing anything else) could have been for a positive or negative number, what do you suggest for the first point then?

  2. I did not realize there was a time when bin did not exist. I agree that that should be added to the documentation.

@seberg
Copy link
Member

seberg commented Mar 6, 2016

I don't know, but I assumed since it was not used in the function ;). But we are going back to python 1.x for this type of functions I think. Not sure, I guess we would have to deprecate it to throw an error also for positive numbers and maybe just throw an error for negative, since it mostly didn't work anyway.

@seberg
Copy link
Member

seberg commented Mar 6, 2016

Uhh, brand new: "New in version 2.6." :)

@gfyoung
Copy link
Contributor Author

gfyoung commented Mar 6, 2016

You mean deprecate behavior when the width parameter is insufficient?

@seberg
Copy link
Member

seberg commented Mar 6, 2016

Yeah, just because if we would prefer error for negative + insufficient width it seems more right to also do it for positive (and I don't really see a good reason to extend width silently). Still thinking about it, but I think I would like it best. Though this is a bug fix foremost I guess.

@gfyoung
Copy link
Contributor Author

gfyoung commented Mar 6, 2016

Fair enough. I'll make that change then.

@gfyoung
Copy link
Contributor Author

gfyoung commented Mar 6, 2016

@seberg : Added the deprecation, and the tests are passing. Can you merge this?

@seberg
Copy link
Member

seberg commented Mar 6, 2016

only after I read it ;p

@gfyoung
Copy link
Contributor Author

gfyoung commented Mar 6, 2016

Touché 😄

binary = bin(twocomp)[2:]
binwidth = len(binary)
outwidth = max(binwidth, width)
warn_if_insufficient(width, binwidth)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we just error out already in this branch? I am not sure, will let you pick.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel more comfortable leaving it as a warning to keep the behaviour consistent for both positive and negative numbers. That was one of the problems brought up in the issue was the response was inconsistent between the two sides.

@seberg
Copy link
Member

seberg commented Mar 6, 2016

Anyway, thanks. Will leave it sitting a bit in case someone disagrees.

@gfyoung
Copy link
Contributor Author

gfyoung commented Mar 6, 2016

Sure thing. I'll ping again in about a week to see if anyone else has anything to add. Would be nice to land this at some point.

@ahaldane
Copy link
Member

ahaldane commented Mar 6, 2016

I, for one, am satisfied. Merge at will!

@gfyoung
Copy link
Contributor Author

gfyoung commented Mar 13, 2016

@seberg , @ahaldane : it has been a week, and I don't see any complaints. Can this be merged (after rebase)?

Completely rewrote binary_repr method to use
the Python's built-in 'bin' function to generate
binary representations quickly.

Fixed the behaviour for negative numbers in which
insufficient widths resulted in outputs of all zero's
for the two's complement. Now, it will return the
two's complement with width equal to the minimum
number of bits needed to represent the complement.

Closes gh-7168.
@njsmith
Copy link
Member

njsmith commented Mar 13, 2016

I haven't reviewed in depth, but it looks like @ahaldane and @seberg both have and are happy and no-one else has spoken up to object, so merging.

njsmith added a commit that referenced this pull request Mar 13, 2016
BUG: Fix binary_repr for negative numbers
@njsmith njsmith merged commit c9aca38 into numpy:master Mar 13, 2016
@gfyoung
Copy link
Contributor Author

gfyoung commented Mar 13, 2016

Thanks @njsmith ! Also thanks to @ahaldane and @seberg for going over this thoroughly.

@gfyoung gfyoung deleted the binary_repr_fix branch March 13, 2016 23:39
@njsmith
Copy link
Member

njsmith commented Mar 13, 2016

Thanks @gfyoung! Sorry we've been so slow getting to your PRs... unfortunately we are pretty short on reviewer time right now :-(

@gfyoung
Copy link
Contributor Author

gfyoung commented Mar 13, 2016

@njsmith : No worries. I understand. I'll just keep pinging regularly and making sure they are relatively up-to-date against the master branch so that @homu is happy.

@njsmith
Copy link
Member

njsmith commented Mar 13, 2016

@gfyoung: the bottleneck is generlaly someone having the time to read through and think about things; once the decision is made then clicking the button isn't a big deal. The practical consequence is that if the merge conflicts are just a trivial issue with the release notes, then please don't waste your time rebasing over and over... just explain the merge conflict being trivial in the ping so it's clear that the relevant content is still reviewable, and then once you get the 👍 you can rebase once then :-)

@gfyoung
Copy link
Contributor Author

gfyoung commented Mar 13, 2016

@njsmith: Fair point.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants