Skip to content

fix: normalize sign when imuln multiplies by zero - #321

Merged
fanatid merged 2 commits into
indutny:masterfrom
spokodev:fix/imuln-zero-negative-zero
Jul 9, 2026
Merged

fanatid merged 2 commits into
indutny:masterfrom
spokodev:fix/imuln-zero-negative-zero

Conversation

@spokodev

@spokodev spokodev commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Multiplying a negative number by the plain number 0 zeroed the words but left the negative flag set, producing a negative zero. That value reported isNeg() as true, was not eq() to zero, compared as less than zero, and printed as -0. new BN(-5).mul(new BN(0)) correctly gives 0; only the imuln/muln path diverged.

This clears the sign along with the length when the factor is zero so the result is a plain zero. The existing zero-multiplication test only checked isZero(), which is true even for a negative zero, so the added test asserts the sign directly.

spokodev and others added 2 commits July 8, 2026 15:02
Multiplying a negative number by the plain number 0 zeroed the words
but left the negative flag set, producing a negative zero. That value
reported isNeg() as true, was not eq() to zero, compared as less than
zero, and printed as -0. Clear the sign along with the length when the
factor is zero so the result is a plain zero.
@fanatid
fanatid merged commit dd84df8 into indutny:master Jul 9, 2026
2 checks passed
fanatid added a commit that referenced this pull request Jul 9, 2026
* fix: correct divRound rounding for negative operands

divRound computed the half-way threshold and the round-up direction
from the raw operands, which only works when both are positive. With a
negative dividend or divisor it compared a signed remainder against a
value derived from the signed divisor, rounded in the wrong direction,
and lost the sign when the truncated quotient was zero.

Compare the magnitude of the remainder against half of the absolute
divisor and step the quotient away from zero using the sign of the
result, so rounding matches the positive case for every sign.

* fix: normalize sign when imuln multiplies by zero (#321)

* fix: normalize sign when imuln multiplies by zero

Multiplying a negative number by the plain number 0 zeroed the words
but left the negative flag set, producing a negative zero. That value
reported isNeg() as true, was not eq() to zero, compared as less than
zero, and printed as -0. Clear the sign along with the length when the
factor is zero so the result is a plain zero.

* use _normSign()

---------

Co-authored-by: Kirill Fomichev <fanatid@ya.ru>

* add more tests

---------

Co-authored-by: Kirill Fomichev <fanatid@ya.ru>
fanatid added a commit that referenced this pull request Jul 9, 2026
* fix: normalize sign when imuln multiplies by zero

Multiplying a negative number by the plain number 0 zeroed the words
but left the negative flag set, producing a negative zero. That value
reported isNeg() as true, was not eq() to zero, compared as less than
zero, and printed as -0. Clear the sign along with the length when the
factor is zero so the result is a plain zero.

* use _normSign()

---------

Co-authored-by: Kirill Fomichev <fanatid@ya.ru>
(cherry picked from commit dd84df8)
fanatid added a commit that referenced this pull request Jul 9, 2026
* fix: correct divRound rounding for negative operands

divRound computed the half-way threshold and the round-up direction
from the raw operands, which only works when both are positive. With a
negative dividend or divisor it compared a signed remainder against a
value derived from the signed divisor, rounded in the wrong direction,
and lost the sign when the truncated quotient was zero.

Compare the magnitude of the remainder against half of the absolute
divisor and step the quotient away from zero using the sign of the
result, so rounding matches the positive case for every sign.

* fix: normalize sign when imuln multiplies by zero (#321)

* fix: normalize sign when imuln multiplies by zero

Multiplying a negative number by the plain number 0 zeroed the words
but left the negative flag set, producing a negative zero. That value
reported isNeg() as true, was not eq() to zero, compared as less than
zero, and printed as -0. Clear the sign along with the length when the
factor is zero so the result is a plain zero.

* use _normSign()

---------

Co-authored-by: Kirill Fomichev <fanatid@ya.ru>

* add more tests

---------

Co-authored-by: Kirill Fomichev <fanatid@ya.ru>
(cherry picked from commit 73fb9a4)
@fanatid

fanatid commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Thank you! Both #320 and #321 published in v4.12.5 and v5.2.5

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants