Files
ladybird/Tests/LibJS/Runtime/operators/multiplication-basic.js
Andreas Kling 710f1bdb74 LibJS: Produce negative zero from i32 multiplication fast path
The i32 multiplication fast path in Mul::execute_impl was producing
+0 instead of -0 when one operand was negative and the other was
zero (e.g. `var a = -1, b = 0; a * b`).

This happened because i32 can't represent -0, so `Value(0)` was
always positive zero. We now fall through to the double path when
the i32 result is zero, which correctly handles the sign.

Also add comprehensive multiplication tests covering negative zero,
basic arithmetic, large integers, type coercion, NaN, and Infinity.
2026-02-08 20:59:20 +01:00

115 lines
2.9 KiB
JavaScript

test("basic multiplication", () => {
expect(3 * 7).toBe(21);
expect(-3 * 7).toBe(-21);
expect(3 * -7).toBe(-21);
expect(-3 * -7).toBe(21);
expect(0 * 0).toBe(0);
expect(1 * 0).toBe(0);
expect(0 * 1).toBe(0);
});
test("multiplication with large integers", () => {
expect(2147483647 * 2).toBe(4294967294);
expect(-2147483648 * -1).toBe(2147483648);
expect(2147483647 * 1).toBe(2147483647);
expect(-2147483648 * 1).toBe(-2147483648);
});
test("negative zero from integer variable multiplication", () => {
var a = -1;
var b = 0;
expect(a * b).toBe(-0);
expect(b * a).toBe(-0);
var c = -100;
expect(c * b).toBe(-0);
expect(b * c).toBe(-0);
var d = -2147483648;
expect(d * b).toBe(-0);
expect(b * d).toBe(-0);
});
test("positive zero from non-negative integer variable multiplication", () => {
var a = 1;
var b = 0;
expect(a * b).toBe(0);
expect(b * a).toBe(0);
expect(Object.is(a * b, -0)).toBeFalse();
expect(Object.is(b * a, -0)).toBeFalse();
var c = 0;
expect(b * c).toBe(0);
expect(Object.is(b * c, -0)).toBeFalse();
});
test("negative zero from compound assignment", () => {
var a = -5;
a *= 0;
expect(a).toBe(-0);
var b = 0;
b *= -5;
expect(b).toBe(-0);
});
test("positive zero from compound assignment", () => {
var a = 5;
a *= 0;
expect(a).toBe(0);
expect(Object.is(a, -0)).toBeFalse();
});
test("negative zero propagation through multiplication", () => {
expect(-0 * 5).toBe(-0);
expect(5 * -0).toBe(-0);
expect(-0 * -5).toBe(0);
expect(-5 * -0).toBe(0);
expect(-0 * 0).toBe(-0);
expect(0 * -0).toBe(-0);
expect(-0 * -0).toBe(0);
});
test("negative zero detectable via division", () => {
var a = -1;
var b = 0;
expect(1 / (a * b)).toBe(-Infinity);
expect(1 / (b * a)).toBe(-Infinity);
var c = 1;
expect(1 / (c * b)).toBe(Infinity);
expect(1 / (b * c)).toBe(Infinity);
});
test("multiplication with non-numeric types", () => {
expect("3" * "7").toBe(21);
expect("" * 5).toBe(0);
expect(null * 5).toBe(0);
expect(false * 5).toBe(0);
expect(true * 5).toBe(5);
expect([] * 5).toBe(0);
});
test("multiplication producing NaN", () => {
expect(NaN * 5).toBeNaN();
expect(5 * NaN).toBeNaN();
expect(undefined * 5).toBeNaN();
expect("foo" * 5).toBeNaN();
});
test("multiplication with Infinity", () => {
expect(Infinity * 2).toBe(Infinity);
expect(-Infinity * 2).toBe(-Infinity);
expect(Infinity * -2).toBe(-Infinity);
expect(-Infinity * -2).toBe(Infinity);
expect(Infinity * Infinity).toBe(Infinity);
expect(Infinity * -Infinity).toBe(-Infinity);
expect(-Infinity * -Infinity).toBe(Infinity);
// Infinity * 0 = NaN
expect(Infinity * 0).toBeNaN();
expect(0 * Infinity).toBeNaN();
expect(-Infinity * 0).toBeNaN();
expect(0 * -Infinity).toBeNaN();
});