fix(pow-x-n): correctness bug — JavaScript iterative solution returns wrong answer for n = INT_MIN - #6044
Open
neetcode-gh wants to merge 1 commit into
Open
fix(pow-x-n): correctness bug — JavaScript iterative solution returns wrong answer for n = INT_MIN#6044neetcode-gh wants to merge 1 commit into
neetcode-gh wants to merge 1 commit into
Conversation
The Binary Exponentiation (Iterative) JavaScript snippet was the only one of the article's nine languages that ran the bit loop on a value that does not fit in a signed 32-bit integer. `Math.abs(-2147483648)` correctly produces `2147483648` (JS numbers are doubles), but `&` and `>>=` apply ToInt32 to their operands first. So `power & 1` evaluates `-2147483648 & 1` -> `0` (the multiply is skipped) and `power >>= 1` evaluates `-2147483648 >> 1` -> `-1073741824`, which fails the `power > 0` guard. The loop exits after a single iteration with `res` still 1. On LeetCode's own published test case `x = 2.00000, n = -2147483648` (expected `0.00000`) the snippet returned `1`. Every other language already widens to 64 bits before the loop -- `Math.abs((long)n)` in Java/C#, `abs((long)n)` in C++, `(n as i64).abs()` in Rust, `n.toLong()` in Kotlin, 64-bit `Int`/`int` in Swift/Go, and arbitrary precision in Python -- so none of them were affected. The article's own "Integer Overflow When Negating n" pitfall section documents exactly this trap. Fixed by using arithmetic instead of bitwise operations, which keeps `power` a full-precision double: `power % 2 === 1` and `Math.floor(power / 2)`. The recursive JavaScript solution already did this and was correct. Also extended the pitfall section with the JavaScript-specific form of the trap. Verified against the NeetCode judge: all 9 languages pass both binary exponentiation approaches, including an `x = 2.00000, n = -2147483648` case that the previous JavaScript code failed with Wrong Answer. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Skipping Bugbot: Bugbot is disabled for this repository. Visit the Bugbot dashboard to update your settings. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
In
articles/pow-x-n.md, the JavaScript snippet for approach 3 (Binary Exponentiation, Iterative) produces a wrong answer forn = -2147483648.x = 2.00000, n = -21474836480.000001.00000That is LeetCode's own published test case for this problem.
Why
Math.abs(-2147483648)is fine on its own — JavaScript numbers are doubles, so it correctly yields2147483648. The problem is the bit loop:&and>>apply ToInt32 to their operands first.So the odd-bit multiply is skipped,
powergoes negative, thepower > 0guard fails, and the loop exits after one iteration withresstill1. The function returns1 / 1 = 1.Why only JavaScript
Every other language in the same tab group already widens the exponent to 64 bits before the loop, so none of them were affected:
Math.abs((long)n)abs((long)n)Math.Abs((long)n)Math.abs(n.toLong())(n as i64).abs()intis 64-bitIntis 64-bitJavaScript was the only one that computed
abscorrectly and then threw the width away again inside the loop.The article's own "Integer Overflow When Negating n" pitfall section warns about exactly this trap, which made the JS snippet the one place in the article that didn't follow its own advice.
The recursive JavaScript solution (approach 2) was already correct — it uses
Math.floor(n / 2)andn % 2, not bitwise ops.The fix
Replace the two bitwise operations with their arithmetic equivalents, which keep
powera full-precision double. Structure, naming, and style are otherwise unchanged, and it now matches how the recursive JS solution already worked.while (power > 0) { - if (power & 1) { + if (power % 2 === 1) { res *= x; } x *= x; - power >>= 1; + power = Math.floor(power / 2); }Also added one sentence to the pitfall section covering the JavaScript-specific form of the trap, so the next reader doesn't "optimize" it back to bitwise.
Verification
Run against the production NeetCode judge with the article-solution harness, using a test set that includes
x = 2.00000, n = -2147483648(expected0.00000):Binary Exponentiation (Iterative)/ javascript — Wrong Answer, 33/34,Expected: 0.00000 / Actual: 1.00000All 9 languages then pass both binary exponentiation approaches (18/18 submissions), confirming JavaScript was the only affected language:
(Approach 1, Brute Force, is
O(n)and times out on the|n| ~ 2^31stress cases by design.)Note for the problem config
The existing
n = -2147483648case in the problem's test set usesx = -1.00000with expected output1.00000. That case does not discriminate this bug:(-1)^(-2^31) = 1, and the broken code also returns1(it exits the loop immediately withres = 1). A case with|x| != 1, such asx = 2.00000, n = -2147483648->0.00000, is what actually catches it, and may be worth adding.🤖 Generated with Claude Code