diff --git a/AUTHORS b/AUTHORS index 09402d47a8..722ec96a87 100644 --- a/AUTHORS +++ b/AUTHORS @@ -287,15 +287,15 @@ Dheemanth D <165369664+Dheemanth07@users.noreply.github.com> Adriano Fantini Chibuike Anselm Jos de Jong +Yarchik rrbharath Lê Vạn Bảo Trọng <32262183+chuanghiduoc@users.noreply.github.com> Hugohong258 -Spoko Dev Yash Goyal <24110399@iitgn.ac.in> Wei-Lun Li -waw666waw666 <184799977+waw666waw666@users.noreply.github.com> wulimammoth kevin <5299031+kevin9327@users.noreply.github.com> WenJing95 <126436871+WenJing95@users.noreply.github.com> +W <184799977+waw666waw666@users.noreply.github.com> # Generated by tools/update-authors.js diff --git a/HISTORY.md b/HISTORY.md index 0c4bd917ec..3c7c18f3ea 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,6 +2,8 @@ # unpublished changes since 15.2.0 +- Fix: Adjust #3710 to ensure that mod of bigints ends up in intended + range for all sign combinations (#3684). Thanks @spokodev. - Fix: #3758 correct gcd and atan2 when computed on arguments including sparse matrices (#3751). Thanks @waw666waw666. - Fix: #3160, #3202 correct TypeScript types for various cases of matrix diff --git a/src/function/arithmetic/mod.js b/src/function/arithmetic/mod.js index 4d2c6cfbd7..36d506e633 100644 --- a/src/function/arithmetic/mod.js +++ b/src/function/arithmetic/mod.js @@ -127,8 +127,8 @@ export const createMod = /* #__PURE__ */ factory(name, dependencies, ({ typed, c } const m = x % y - - if (x < 0 || y < 0) return m === 0n ? m : m + y - return m + // Ensure result m is always in desired range: 0 ≤ m < y for y positive, + // y < m ≤ 0 for y negative: + return m !== 0n && (m < 0n) !== (y < 0n) ? m + y : m } }) diff --git a/test/unit-tests/function/arithmetic/invmod.test.js b/test/unit-tests/function/arithmetic/invmod.test.js index f5b2bfde9c..e1f59fab1d 100644 --- a/test/unit-tests/function/arithmetic/invmod.test.js +++ b/test/unit-tests/function/arithmetic/invmod.test.js @@ -42,6 +42,8 @@ describe('invmod', function () { it('should calculate invmod for bigints', function () { assert.strictEqual(invmod(5n, 13n), 8n) assert.strictEqual(invmod(6n, -17n), -14n) + assert.strictEqual(invmod(2n, -7n), -3n) + assert.strictEqual(invmod(5n, -13n), -5n) }) it('should calculate invmod for mixed BigNumbers and Numbers', function () { diff --git a/test/unit-tests/function/arithmetic/mod.test.js b/test/unit-tests/function/arithmetic/mod.test.js index f257eae1eb..f266e21625 100644 --- a/test/unit-tests/function/arithmetic/mod.test.js +++ b/test/unit-tests/function/arithmetic/mod.test.js @@ -48,6 +48,15 @@ describe('mod', function () { assert.strictEqual(mod(-8n, 4n), 0n) }) + it('should calculate the modulus of bigints for a negative divisor', function () { + assert.strictEqual(mod(10n, -4n), -2n) + assert.strictEqual(mod(-10n, -4n), -2n) + assert.strictEqual(mod(8n, -3n), -1n) + assert.strictEqual(mod(-8n, -3n), -2n) + assert.strictEqual(mod(8n, -4n), 0n) + assert.strictEqual(mod(-8n, -4n), 0n) + }) + it('should handle precise approximation of float approximation', function () { approxEqual(mod(0.1, 0.01), 0) approxEqual(mod(0.15, 0.05), 0) @@ -111,6 +120,8 @@ describe('mod', function () { assert.strictEqual(mod(14, 8n), 6n) assert.strictEqual(mod(12.5, 37n), 12.5) assert.strictEqual(mod(14n, 8.5), 5.5) + assert.strictEqual(mod(-10, -4n), -2n) + assert.strictEqual(mod(-10n, -4), -2n) }) it('should calculate the modulus of mixed booleans and bignumbers', function () {