Uh oh!
There was an error while loading. Please reload this page.
Make Int::pow() take exp as u32 instead usize - #22087
Conversation
rust-highfive
commented
Feb 8, 2015
(rust_highfive has picked a reviewer for you, use r? to override) |
dotdash
commented
Feb 8, 2015
It would be great if the commit subject mentioned what's being done here, for example: And then just put the "Fixes #22016" in the commit message body. |
GuillaumeGomez
commented
Feb 8, 2015
My bad, I change that ! |
dotdash
commented
Feb 8, 2015
It should be possible keep the implementation as a default method if you switch from But one might argue that using |
GuillaumeGomez
commented
Feb 8, 2015
As long as it's not merged, I can modify. However, yes, I think that the "clear" code is better in this case. It makes the reading easier (even if that's not a big problem in this case). Whatever, let's wait others' opinion. |
pczarn
commented
Feb 9, 2015
Consider negative exponents. With this PR, I think you can write |
GuillaumeGomez
commented
Feb 9, 2015
@pczarn: I was actually wondering if the negative powers should be handled... |
pczarn
commented
Feb 9, 2015
In my opinion
Add tests to libcoretest if you choose to add these conditions. |
GuillaumeGomez
commented
Feb 9, 2015
I'll wait other opinions before doing anything but that seems a good idea. |
alexcrichton
commented
Feb 9, 2015
It's a bit of an open question as to what the best option for an argument here is. Strictly speaking I'm not sure that we need a range outside of |
GuillaumeGomez
commented
Feb 10, 2015
I added the changes proposed by @pczarn and tests. Now waiting for something definitive. |
Diggsey
commented
Feb 11, 2015
Using "Self" is wrong, because exponentiation is fundamentally different from addition/multiplication (think about units, you can't have 1m ^ 1m, it just doesn't make sense). You can use any non-negative integer as the exponent without necessarily overflowing even the smallest type (1^n == 1). You might think that's not particularly useful if the only valid base is either "1" or "0", but it means you don't have to handle that case specially. Similarly the type of the exponent doesn't affect the return type (u8 ^ u64 == u8) so you don't suffer from larger integer types "leaking" into the rest of the program, as you would do if you applied this logic to the other integer operations. You may as well use the largest integer type which won't harm performance (ie. either usize or u64). Another way of looking at it, is by considering it as repeated multiplication: There's absolutely no reason why the type of "n" should relate to the type of "base". It's limit is only related to the maximum number of times a loop can be expected to iterate (for which one would normally use the largest built-in integer type). (somewhat related: C is going to be using intmax_t for its pown function, which performs integer exponentiation on floats: http://stackoverflow.com/a/23872884) |
GuillaumeGomez
commented
Feb 11, 2015
I think the proposition of @alexcrichton is actually the best one. Limit the pow to u8 would be more than enough. But it's nice to create a little debate sometimes ! |
alexcrichton
commented
Feb 11, 2015
@GuillaumeGomez oh to be clear I was not advocating for |
GuillaumeGomez
commented
Feb 12, 2015
The big question which remains is: do we pass Self as exp or not ? |
brson
commented
Feb 18, 2015
On IRC I chimed in to suggest this should be u32, along with the other shifting and counting methods on Also that overflow doesn't appear to be handled #22506. |
GuillaumeGomez
commented
Feb 18, 2015
That's what @alexcrichton came along with too. So I think I'll do it with u32. Now, it remains the following question: panic or not when overflow ? |
Gankra
commented
Feb 19, 2015
It makes sense to me to have whatever panic semantics integer overflow has for any other arithmetic operation. This may involve cfgs for debug/ndebug, though I honestly haven't tracked what the settled integer overflow behaviour is. |
GuillaumeGomez
commented
Feb 19, 2015
Okay ! Then I just have to implement it ! |
GuillaumeGomez
commented
Feb 19, 2015
pnkfelix
commented
Feb 23, 2015
cc #22240 |
There was a problem hiding this comment.
I'm a little confused by these overflow semantics. How come the overflow is only registered on the next iteration of the loop? Additionally, how come overflow is registered at all? In theory this has the same overflow semantics as a * b which is actually listed below (with base * base) so isn't overflow naturally detected?
There was a problem hiding this comment.
When the base overflows on the last iteration, it does not corrupt the returned result and should not cause a panic. This is an edge case I discovered working on the arith-overflow branch.
There was a problem hiding this comment.
(Having said that, I prefer my encoding of this semantics, given in the gist linked above)
There was a problem hiding this comment.
That's I what I couldn't completely understand : if we panic, why should we
give attention to the returned result ?
Le 24 févr. 2015 09:54, "Felix S Klock II" notifications@github.com a
écrit :
In src/libcore/num/mod.rs
#22087 (comment):@@ -464,6 +452,30 @@ macro_rules! uint_impl {
v => Some(self / v),
}
}
+
#[inline]fn pow(self, mut exp: u32) -> Self {let mut base = self;let mut acc: Self = Int::one();let mut did_base_overflow = false;while exp > 0 {if (exp & 1) == 1 {acc = acc \* base;if did_base_overflow {panic!("overflow detected");}(Having said that, I prefer my encoding of this semantics, given in the
gist linked above)—
Reply to this email directly or view it on GitHub
https://github.com/rust-lang/rust/pull/22087/files#r25236519.
There was a problem hiding this comment.
@GuillaumeGomez I fear I do not understand your question.
It seems like you are asking "why do we care about the returned result in the cases where we panic?" When we panic, of course there is no returned result. I care about enforcing the following rule: panic if and only if the accumulated acc (the "to-be-returned result") has been corrupted by an overflow. If we panic, then I want the reason to be because the accumulated value has become useless. I do not want to panic merely because the computation base * base overflows when its resulting value is never actually used.
From @alexcrichton 's comment, it sounds like he is assuming that your code was written in the context of a version of Rust that panics on overflow from operations like base * base. (While on the other hand, you have written your code to still panic on overflow even in a context where base * base itself does not.) If you look at my gist, it deliberately uses a version of multiply for the base * base squaring computation at the end of each iteration that does not cause a panic when that squaring overflows. You would need to change your code to also use that variant if you want to ensure that the base * base computation does not itself immediately panic.
There was a problem hiding this comment.
You perfectly replied to my question ! @alexcrichton gave me doubts.
Le 24 févr. 2015 11:09, "Felix S Klock II" notifications@github.com a
écrit :
In src/libcore/num/mod.rs
#22087 (comment):@@ -464,6 +452,30 @@ macro_rules! uint_impl {
v => Some(self / v),
}
}
+
#[inline]fn pow(self, mut exp: u32) -> Self {let mut base = self;let mut acc: Self = Int::one();let mut did_base_overflow = false;while exp > 0 {if (exp & 1) == 1 {acc = acc \* base;if did_base_overflow {panic!("overflow detected");}@GuillaumeGomezhttps://github.com/GuillaumeGomez I fear I do not
understand your question.It seems like you are asking "why do we care about the returned result in
the cases where we panic?" When we panic, of course there is no returned
result. I care about enforcing the following rule: panic if and only if
the accumulated acc (the "to-be-returned result") has been corrupted by
an overflow. If we panic, then I want to to be because the accumulated
value has become useless. I do not want to panic merely because the
computation base * base overflows when its resulting value is never
actually used.From @alexcrichtonhttps://github.com/alexcrichton 's comment, it
sounds like he is assuming that your code was written in the context of a
version of Rust that panics on overflow from operations like base * base.
(While on the other hand, you have written your code to still panic on
overflow even in a context where base * base itself does not.) If you
look at my gist, it deliberately uses a version of multiply for the base
- base squaring computation at the end of each iteration that does not
cause a panic when that squaring overflows. You would need to change your
code to also use that variant if you want to ensure that the base * base
computation does not itself immediately panic.—
Reply to this email directly or view it on GitHub
https://github.com/rust-lang/rust/pull/22087/files#r25241010.
alexcrichton
commented
Feb 24, 2015
@GuillaumeGomez can you change this PR to only update |
GuillaumeGomez
commented
Feb 24, 2015
As soon as I have a computer, I do that. Oterwise he can just rebase on my
|
pnkfelix
commented
Feb 24, 2015
@GuillaumeGomez i don't know how long its going to take me to get arith-oflo landed. Please land this change on its own, in a rollup if you like, I guess. |
pnkfelix
commented
Feb 24, 2015
@GuillaumeGomez (or, if you will not have access to time or a computer in the near future, I can take over this PR for you. I largely don't want to mix this API change in with the arith-oflo work; they are distinct efforts.) |
GuillaumeGomez
commented
Feb 24, 2015
Ok I do that (tomorrow) !
|
GuillaumeGomez
commented
Feb 24, 2015
My actual computer is dead, i'm supposed to receive the new one by the end
|
GuillaumeGomez
commented
Feb 26, 2015
I removed the under/overflow handling. @pnkfelix: you can take it on now ! @alexcrichton: waiting for you now. |
There was a problem hiding this comment.
Would it be possible to leave the default method implementation for these methods? It looks like both impls are the same currently.
There was a problem hiding this comment.
It was in prevision for under/overflow handling. But if you want yes I can.
GuillaumeGomez
commented
Feb 27, 2015
@alexcrichton: squashed |
alexcrichton
commented
Feb 27, 2015
Did some extra commits leak in? |
GuillaumeGomez
commented
Feb 27, 2015
Finally solved... |
alexcrichton
commented
Feb 27, 2015
It looks like there are still some extra commits here (there should probably just be one) |
GuillaumeGomez
commented
Feb 27, 2015
There isn't anymore. |
GuillaumeGomez
commented
Feb 27, 2015
Done. |
GuillaumeGomez
commented
Feb 28, 2015
I squashed the remaining commits and rename it. |
alexcrichton
commented
Feb 28, 2015
@bors: r+ 73ce70807e6c5f97206323429463018ab40a2eec |
bors
commented
Feb 28, 2015
⌛ Testing commit 73ce708 with merge c1e597c... |
bors
commented
Feb 28, 2015
💔 Test failed - auto-mac-32-opt |
Manishearth
commented
Feb 28, 2015
(snippet of error, there are more) |
GuillaumeGomez
commented
Mar 1, 2015
I updated to master and I fixed tests. Waiting for rollup. @alexcrichton@Manishearth |
alexcrichton
commented
Mar 1, 2015
bors
commented
Mar 1, 2015
bors
commented
Mar 1, 2015
`Int::pow()` takes u32 instead of usize; see rust-lang/rust#22087.
fix: Fix incorrect lifetime hints for self with type
fix: Fix incorrect lifetime hints for self with type
Fixes issue #22016