An abstract operation is a conceptual operation that is not an actual operation in the language but is used to aid in the specification and understanding of a programming concept or system.

The following abstract operations are defined over the Number object:

Operation Example Invoked by Result
Number::unaryMinus -x Unary - Operator Number
Number::bitwiseNOT ~x Bitwise NOT Operator (~) Number
Number::exponentiate x ** y Exponentiation Operator (**) and Math.pow(base, exponent) Number
Number::multiply x * y Multiplicative Operators Number
Number::divide x / y Multiplicative Operators Number
Number::remainder x % y Multiplicative Operators Number
Number::add x ++
++ x
x + y
Postfix Increment Operator, Prefix Increment Operator, and The Addition Operator (+) Number
Number::subtract x --
-- x
x - y
Postfix Decrement Operator, Prefix Decrement Operator, and The Subtraction Operator (-) Number
Number::leftShift x << y The Left Shift Operator(<<) Number
Number::signedRightShift x >> y The Signed Right Shift Operator(>>) Number
Number::unsignedRightShift x >>> y The Unsigned Right Shift Operator (>>>) Number
Number::unsignedRightShift x >>> y The Unsigned Right Shift Operator (>>>) Number
Number::lessThan x < y
x > y
x <= y
x >= y
Relational Operators, via IsLessThan (x, y, LeftFirst) Boolean or undefined (for unordered inputs)
Number::equal x == y
x != y
x === y
x !== y
Equality Operators, via IsStrictlyEqual (x, y) Boolean
Number::sameValue Object.is(x, y) Object internal methods, via SameValue (x, y), to test exact value equality Boolean
Number::sameValueZero [x].includes(y) Array, Map, and Set methods, via SameValueZero (x, y), to test value equality, ignoring the difference between +0 and -0 Boolean
Number::bitwiseAND x & y Binary Bitwise Operators Number
Number::bitwiseXOR x ^ y Number
Number::bitwiseOR x | y Number
Number::toString String(x) Many expressions and built-in functions, via ToString (argument) String
Number::unaryMinus(x)

The abstract operation Number::unaryMinus takes argument x (a Number) and returns a Number. It performs the following steps when called:

  1. If x is NaN, return NaN.
  2. Return the result of negating x; that is, compute a Number with the same magnitude but opposite sign.

If we translated the steps into Javascript codes, this is more or less it would look like:

Number.unaryMinus = function(x) {
            if (Number.isNaN(x)) {
                // if x is NaN, return NaN
                return Number.NaN;
            } else {
                // return the result of negating
                return Number(-x);
            }
        };
        Number.unaryMinus(Number(100));
Number::bitwiseNOT(x)

The abstract operation Number::bitwiseNOT takes argument x (a Number) and returns a Number. It performs the following steps when called:

  1. Let oldValue be !ToInt32(x)
  2. Return the result of applying bitwise complement to oldValue. The mathematical value of the result is exactly representable as a 32-bit two's complement bit string.

The !ToInt32(x) just means that we are certain that this call to ToInt32 will never return an exception

If we translated the steps into Javascript codes, this is more or less it would look like:

Number.bitwiseNOT = function(x) {
    // return the result of applying bitwise complement to x
    return Number(~x);
};
Number.bitwiseNOT(Number(100));
Number::exponentiate (base, exponent)

The abstract operation Number::exponentiate takes arguments base (a Number) and exponent (a Number) and returns a Number. It returns an implementation-approximated value representing the result of raising base to the exponent power. It performs the following steps when called:

  1. If exponent is NaN, return NaN.
  2. If exponent is either +0 or -0, return 1.
  3. If base is NaN, return NaN.
  4. If base is +∞, then
    1. If exponent > +0, return +∞. Otherwise, return +0
  5. If base is -∞, then
    1. If exponent > +0, then
      1. If exponent is an odd integral Number, return -∞. Otherwise, return +∞.
    2. Else
      1. If exponent is an odd integral Number, return -0. Otherwise, return +0.
  6. If base is +0, then
    1. If exponent > +0, return +0. Otherwise, return +∞.
  7. If base is -0, then
    1. If exponent > +0, return +0. Otherwise, return +∞.
      1. If exponent is an odd integral Number, return -0. Otherwise, return +0.
    2. Else,
      1. If exponent is an odd integral Number, return -∞. Otherwise, return +∞.
  8. Assert: base is finite and is neither +0 nor -0.
  9. If exponent is +∞, then
    1. If abs(base) > 1, return +∞.
    2. If abs(base) = 1, return NaN.
    3. If abs(base) < 1, return +0.
  10. If exponent is -∞, then
    1. If abs(base) > 1, return +0.
    2. If abs(base) = 1, return NaN.
    3. If abs(base) < 1, return +∞.
  11. Assert: exponent is finite and is neither +0 nor -0.
  12. If base < -0 and exponent is not an integral Number, return NaN.
  13. Return an implementation-approximated Number value representing the result of raising base to the exponent power.
Number.exponentiate = function(base, exponent) {
    if(Number.isNaN(exponent)) {
        // if exponent is NaN, return NaN
        return Number.NaN;
    }
    if(Number(exponent) === 0) {
        // if exponent is either +0 or -0, return 1
        return 1;
    }
    if(Number.isNaN(base)) {
        // if base is NaN, return NaN
        return Number.NaN;
    }
    if(Number(base) === +Infinity) {
        // if base is +∞
        if(Number(exponent) > 0) {
            // if exponent > +0, return +∞
            return +Infinity;
        } else {
            // otherwise, return +0
            return Number(0);
        }
    }
    if(Number(base) === -Infinity) {
        // if base is -∞, then
        if(Number(exponent) > 0) {
            // if exponent > +0, then
            if(Number(exponent) % 2 === 1) {
                // if exponent is an odd integral Number, return -∞
                return -Infinity;
            }
            else {
                // otherwise, return +∞
                return +Infinity;
            }
        } else {
            // else
            if(Number(exponent) % 2 === 1) {
                // if exponent is an odd integral Number, return -0
                return Number(-0);
            }
            else {
                // otherwise, return +0.
                return Number(0);
            }
        }
    }
    if(Number(base) === Infinity) {
        // f base is +∞, then
        if(Number(exponent) > 0) {
            // If exponent > +0, return +∞
            return Infinity;
        }
        else {
            // Otherwise, return +0
            return Number(0);
        }
    }
    if(Number(base) === -Infinity) {
        // if base is -∞, then
        if(exponent > 0) {
            // if exponent > +0 then
            if(exponent % 2 === 1) {
                // if exponent is an odd integral Number, return -∞
                return -Infinity;
            }
            else {
                // otherwise, return +∞
                return Infinity;
            }
        }
        else {
            // else
            if(exponent % 2 === 1) {
                // if exponent is an odd integral Number, return -0
                return Number(-0);
            }
            else {
                // otherwise, return +0
                return Number(0);
            }
        }
    }
    if(1/Number(base) === Infinity) {
        // if base is +0, then
        if(Number(exponent) > 0) {
            // if exponent > +0, return +0
            return Number(0);
        }
        else {
            // otherwise, return +∞
            return Infinity;
        }
    }
    if(1/Number(base) === -Infinity) {
        // if base is -0, then
        if(Number(exponent) > 0) {
            // if exponent > +0 then
            if(Number(exponent) % 2 === 1) {
                // if exponent is an odd integral Number, return -0
                return Number(-0);
            }
            else {
                // Otherwise, return +0
                return Number(0);
            }
        }
        else {
            // else
            if(Number(exponent) % 2 === 1) {
                // if exponent is an odd integral Number, return -∞
                return -Infinity;
            }
            else {
                // otherwise, return +∞
                return Infinity;
            }
        }
    }
    // base is finite and is neither +0 nor -0
    if(exponent === Infinity) {
        // if exponent is +∞, then
        if(Math.abs(base) > 1) {
            // if abs(base) > 1, return +∞
            return Infinity;
        }
        if(Math.abs(base) === 1) {
            // if abs(base) = 1, return NaN
            return Number.NaN;
        }
        if(Math.abs(base) <  1) {
            // If abs(base) < 1, return +0
            return Number(0);
        }
    }

    if(exponent === -Infinity) {
        // if exponent is -∞, then
        if(Math.abs(base) > 1) {
            // if abs(base) > 1, return +0
            return Number(0);
        }
        if(Math.abs(base) === 1) {
            // if abs(base) = 1, return NaN.
            return Number.NaN;
        }
        if(Math.abs(base) <  1) {
            // if abs(base) < 1, return +∞
            return Infinity;
        }
    }

    // exponent is finite and is neither +0 nor -0
    if(base < 0 && Math.isNaN(exponent)) {
        // if base < -0 and exponent is not an integral Number, return NaN.
        return Number.NaN;
    }
    // return an implementation-approximated Number value representing the result of raising base to the exponent power.
    return Number(base) ** Number(exponent);
};
Number.exponentiate(Number(2), Number(1.2));
Number::multiply (x, y)

The abstract operation Number::multiply takes arguments x (a Number) and y (a Number) and returns a Number. It performs multiplication according to the rules of IEEE 754-2019 binary double-precision arithmetic, producing the product of x and y. It performs the following steps when called:

  1. If x is NaN or y is NaN, return NaN.
  2. If x is either +∞ or -∞, then
    1. If y is either +0 or -0, return NaN.
    2. If y > +0, return x.
    3. Return -x.
  3. If y is either +∞ or -∞, then
    1. If x is either +0 or -0, return NaN.
    2. If x > +0, return y.
    3. Return -y.
  4. If x is -0, then
    1. If y is -0 or y < -0, return +0.
    2. Else, return -0.
  5. If y is -0, then
    1. If x < -0, return +0.
    2. Else, return -0.
  6. Return x × y.

If we translated the steps into Javascript codes, this is more or less it would look like:

Number.multiply = function(x, y) {
    if(Number.isNaN(x) || Number.isNaN(y)) {
        // if x is NaN or y is NaN, return NaN
        return Number.NaN;
    }
    if(Number(x) === +Infinity || Number(x) === -Infinity) {
        // if x is either +∞ or -∞, then
        if(1/Number(y) === +Infinity || 1/Number(y) === -Infinity) {
            // If y is either +0 or -0, return NaN
            return Number.NaN;
        }

        if(Number(y) > 0) {
            // If y > +0, return x
            return Number(x);
        }
        // Return -x
        return Number(-x);
    }
    if(Number(y) === +Infinity || Number(y) === -Infinity) {
        // if y is either +∞ or -∞, then
        if(Number(x) === 0) {
            // if x is either +0 or -0, return NaN.
            return Number.NaN;
        }
        if(Number(x) > 0) {
            // if x > +0, return y.
            return Number(y);
        }
        // Return -y
        return Number(-y);
    }
    if(1/Number(x) === -Infinity) {
        // If x is -0, then
        if(1/Number(y) === -Infinity || y < 0) {
            // If y is -0 or y < -0, return +0
            return Number(0);
        } else {
            // Else, return -0
            return Number(-0);
        }
    }
    if(1/Number(-y) === -Infinity) {
        // If y is -0, then
        if(x < 0) {
            // If x < -0, return +0
            return Number(0);
        }
        else {
            // Else, return -0
            return Number(-0);
        }
    }
    // Return x × y
    return Number(x) * Number(y);
};
Number.multiply(Number(1.5), Number(23.76));
Number::divide (x, y)

The abstract operation Number::divide takes arguments x (a Number) and y (a Number) and returns a Number. It performs division according to the rules of IEEE 754-2019 binary double-precision arithmetic, producing the quotient of x and y where x is the dividend and y is the divisor. It performs the following steps when called:

  1. If x is NaN or y is NaN, return NaN.
  2. If x is either +∞ or -∞, then
    1. If y is either +∞ or -∞, return NaN.
    2. If y is +0 or y > +0, return x.
    3. Return -x.
  3. If y is +∞, then
    1. If x is +0 or x > +0, return +0. Otherwise, return -0.
  4. If y is -∞, then
      If x is +0 or x > +0, return -0. Otherwise, return +0.
  5. If x is either +0 or -0, then
    1. If y is either +0 or -0, return NaN.
    2. If y > +0, return x.
    3. Return -x.
  6. If y is +0, then
    1. If x > +0, return +∞. Otherwise, return -∞.
  7. If y is -0, then
  8. If x > +0, return -∞. Otherwise, return +∞.
  9. Return x / y.

If we translated the steps into Javascript codes, this is more or less it would look like:

Number.divide = function(x, y) {
    if(Number.isNaN(x) || Number.isNaN(y)) {
        // if x is NaN or y is NaN, return NaN
        return Number.NaN;
    }
    if(Number(x) === +Infinity || Number(x) === -Infinity) {
        // if x is either +∞ or -∞, then
        if(Number(y) === +Infinity || Number(y) === -Infinity) {
            // If y is either +∞ or -∞, return NaN
            return Number.NaN;
        }
        if(1/Number(y) === Infinity ||  Number(y) > 0) {
            // If y is +0 or y > +0, return x
            return Number(x);
        }
        // Return -x
        return Number(-x);
    }
    if(Number(y) === +Infinity) {
        // If y is +∞, then
        if(1/Number(x) === Infinity || Number(x) > 0) {
            // If x is +0 or x > +0, return +0
            return Number(0);
        }
        else {
            // Otherwise, return -0
            return Number(-0);
        }
    }
    if(Number(y) === -Infinity) {
        // If y is -∞, then
        if(1/Number(x) === Infinity || x > 0) {
            // If x is +0 or x > +0, return -0
            return Number(-0);
        } else {
            // Otherwise, return +0
            return Number(+0);
        }
    }
    if(Number(x) === 0) {
        // If x is either +0 or -0, then
        if(Number(y) === 0) {
            // If y is either +0 or -0, return NaN.
            return Number.NaN;
        }
        if(Number(y) > 0) {
            // If y > +0, return x
            return Number(x);
        }
        // Return -x
        return Number(-x);
    }
    if(1/Number(y) === Infinity) {
        // If y is +0, then
        if(Number(x) > 0) {
            // If x > +0, return +∞
            return Infinity;
        }
        else {
            // Otherwise, return -∞
            return -Infinity;
        }
    }
    if(1/Number(y) === -Infinity) {
        // If y is -0, then
        if(x > 0) {
            // If x > +0, return -∞
            return -Infinity;
        }
        else {
            // Otherwise, return +∞
            return Infinity;
        }
    }

    // Return x / y
    return Number(x) / Number(y);
};
Number.divide(Number(1.5), Number(23.76));
Number::remainder (n, d)

The abstract operation Number::remainder takes arguments n (a Number) and d (a Number) and returns a Number. It yields the remainder from an implied division of its operands where n is the dividend and d is the divisor. It performs the following steps when called:

  1. If n is NaN or d is NaN, return NaN.
  2. If n is either +∞ or -∞, return NaN.
  3. If d is either +∞ or -∞, return n.
  4. If d is either +0 or -0, return NaN.
  5. If n is either +0 or -0, return n.
  6. Assert: n and d are finite and non-zero.
  7. Let quotient be n / d.
  8. Let q be truncate(quotient).
  9. Let r be n - (d × q).
  10. If r = 0 and n < -0, return -0.
  11. Return r.

The mathematical function truncate(x) removes the fractional part of x by rounding towards zero, producing -floor(-x) if x < 0 and otherwise producing floor(x).

If we translated the steps into Javascript codes, this is more or less it would look like:

Number.remainder = function(n, d) {
    if(Number.isNaN(n) || Number.isNaN(d)) {
        // If n is NaN or d is NaN, return NaN
        return Number.NaN;
    }
    if(Number(n) === +Infinity || Number(n) === -Infinity) {
        // If n is either +∞𝔽 or -∞𝔽, return NaN
        return Number.NaN;
    }
    if(Number(d) === +Infinity || Number(d) === -Infinity) {
        // If d is either +∞ or -∞, return n
        return Number(d);
    }
    if(Number(d) === 0) {
        // If d is either +0 or -0, return NaN
        return Number.NaN;
    }
    if(Number(n) === 0) {
        // If n is either +0 or -0, return n
        return Number(n);
    }

    // let quotient be n / d
    let quotient = n / d;
    
    // let q be truncate(quotient)
    let q = Math.floor(quotient);

    // let r be n - (d × q)
    let r = n - (d * q);

    if(r === 0 && n < 0) {
        // if r = 0 and n < -0, return -0
        return Number(-0);
    }
    
    // Return r
    return Number(r);
};
Number.remainder(Number(1.5), Number(23.76));
Number::add (x, y)

The abstract operation Number::add takes arguments x (a Number) and y (a Number) and returns a Number. It performs addition according to the rules of IEEE 754-2019 binary double-precision arithmetic, producing the sum of its arguments. It performs the following steps when called:

  1. If x is NaN or y is NaN, return NaN.
  2. If x is +∞ and y is -∞, return NaN.
  3. If x is -∞ and y is +∞, return NaN.
  4. If x is either +∞ or -∞, return x.
  5. If y is either +∞ or -∞, return y.
  6. Assert: x and y are both finite.
  7. If x is -0 and y is -0, return -0.
  8. Return x + y.

If we translated the steps into Javascript codes, this is more or less it would look like:

Number.add = function(x, y) {
    if(Number.isNaN(x) || Number.isNaN(y)) {
        // If x is NaN or y is NaN, return NaN
        return Number.NaN;
    }
    if(Number(x) === +Infinity && Number(y) === -Infinity) {
        // If x is +∞ and y is -∞, return NaN
        return Number.NaN;
    }
    if(Number(x) === -Infinity && Number(y) === Infinity) {
        // If x is -∞ and y is +∞, return NaN.
        return Number.NaN;
    }
    if(Number(x) === Infinity || Number(x) === -Infinity) {
        // If x is either +∞ or -∞, return x
        return Number(x);
    }
    if(Number(y) === Infinity || Number(y) === -Infinity) {
        // If y is either +∞ or -∞, return y
        return Number(y);
    }
    // x and y are both finite
    if(1/Number(x) === -Infinity && 1/Number(y) === -Infinity) {
        // If x is -0 and y is -0, return -0
        return Number(-0);
    }
    
    // Return x + y
    return Number(x) + Number(y);
};
Number.add(Number(73.5), Number(23.76));
Number::subtract (x, y)

The abstract operation Number::subtract takes arguments x (a Number) and y (a Number) and returns a Number. It performs subtraction, producing the difference of its operands; x is the minuend and y is the subtrahend. It performs the following steps when called:

  1. Return Number::add(x, Number::unaryMinus(y))
Number::leftShift (x, y)

The abstract operation Number::leftShift takes arguments x (a Number) and y (a Number) and returns an integral Number. It performs the following steps when called:

  1. Let lnum be !ToInt32(x).
  2. Let rnum be !ToUint32(y).
  3. Let shiftCount be rnum modulo 32.
  4. Return the result of left shifting lnum by shiftCount bits. The mathematical value of the result is exactly representable as a 32-bit two's complement bit string.

The !ToInt32(x) just means that we are certain that this call to ToInt32 will never return an exception.

If we translated the steps into Javascript codes, this is more or less it would look like:

Number.leftShift = function (x, y) {
    // lnum is the value of x converted to 32 bit integer
    // rnum is the value of y converted to 32 bit unsigned integer
    let lnum = x;
    let rnum = y;

    // Let shiftCount be rnum modulo 32
    let shiftCount = rnum % 32;

    // Return the result of left shifting lnum by shiftCount bits
    return lnum << shiftCount;
};
Number.leftShift(20, 5);
Number::signedRightShift (x, y)

The abstract operation Number::signedRightShift takes arguments x (a Number) and y (a Number) and returns an integral Number. It performs the following steps when called:

  1. Let lnum be !ToInt32(x).
  2. Let rnum be !ToUint32(y).
  3. Let shiftCount be rnum modulo 32.
  4. Return the result of performing a sign-extending right shift of lnum by shiftCount bits. The most significant bit is propagated. The mathematical value of the result is exactly representable as a 32-bit two's complement bit string.

When the most significant bit (MSB) is propagated, it means that the value of the MSB is copied and shifted into the vacant positions during a right shift operation. As a result, the sign of the original number is preserved, and the MSB, which indicates the sign of the number, is replicated and moved to the right. This process is also referred to as an arithmetic shift.

If we translated the steps into Javascript codes, this is more or less it would look like:

Number.signedRightShift = function (x, y) {
    // lnum is the value of x converted to 32 bit integer
    // rnum is the value of y converted to 32 bit unsigned integer
    let lnum = x;
    let rnum = y;

    // Let shiftCount be rnum modulo 32
    let shiftCount = rnum % 32;

    // Return the result of performing a sign-extending right shift of lnum by shiftCount bits
    return lnum >> shiftCount;
};
Number.signedRightShift(320, 5);
Number::unsignedRightShift (x, y)

The abstract operation Number::unsignedRightShift takes arguments x (a Number) and y (a Number) and returns an integral Number. It performs the following steps when called:

  1. Let lnum be !ToUint32(x).
  2. Let rnum be !ToUint32(y).
  3. Let shiftCount be rnum modulo 32.
  4. Return the result of performing a zero-filling right shift of lnum by shiftCount bits. Vacated bits are filled with zero. The mathematical value of the result is exactly representable as a 32-bit unsigned bit string.

If we translated the steps into Javascript codes, this is more or less it would look like:

Number.unsignedRightShift = function (x, y) {
    // lnum is the value of x converted to 32 bit unsigned integer
    // rnum is the value of y converted to 32 bit unsigned integer
    let lnum = x;
    let rnum = y;

    // Let shiftCount be rnum modulo 32
    let shiftCount = rnum % 32;

    // Return the result of performing a sign-extending right shift of lnum by shiftCount bits
    return lnum >>> shiftCount;
};
Number.unsignedRightShift(320, 5);
Number::lessThan (x, y)

The abstract operation Number::lessThan takes arguments x (a Number) and y (a Number) and returns a Boolean or undefined. It performs the following steps when called:

  1. If x is NaN, return undefined.
  2. If y is NaN, return undefined.
  3. If x is y, return false.
  4. If x is +0 and y is -0, return false.
  5. If x is -0 and y is +0, return false.
  6. If x is +∞, return false.
  7. If y is +∞, return true.
  8. If y is -∞, return false.
  9. If x is -∞, return true.
  10. Assert: x and y are finite and non-zero.
  11. If x < y, return true. Otherwise, return false.

If we translated the steps into Javascript codes, this is more or less it would look like:

Number.lessThan = function (x, y) {
    if(Number.isNaN(x)) {
        // If x is NaN, return undefined
        return undefined;
    }
    if(Number.isNaN(y)) {
        // If y is NaN, return undefined
        return undefined;
    }
    if(x === y) {
        // If x is y, return false
        return false;
    }
    if(1/Number(x) === Infinity && 1/Number(y) === -Infinity) {
        // If x is +0 and y is -0, return false
        return false;
    }
    if(1/Number(x) === -Infinity && 1/Number(y) === Infinity) {
        // If x is -0 and y is +0, return false
        return false;
    }
    if(x === Infinity) {
        // If x is +∞, return false
        return false;
    }
    if(y === Infinity) {
        // If y is +∞, return true
        return true;
    }
    if(y === -Infinity) {
        // If y is -∞, return false
        return false;
    }
    if(x === -Infinity) {
        // If x is -∞, return true.
        return true;
    }
    // x and y are finite and non-zero
    
    // If x < y, return true
    if(Number(x) < Number(y)) {
        return true;
    }
    else {
        return false;
    }
};
Number.lessThan(30, 50);
Number::equal(x, y)

The abstract operation Number::equal takes arguments x (a Number) and y (a Number) and returns a Boolean. It performs the following steps when called:

  1. If x is NaN, return false.
  2. If y is NaN, return false.
  3. If x is y, return true.
  4. If x is +0 and y is -0, return true.
  5. If x is -0 and y is +0, return true.
  6. Return false.

If we translated the steps into Javascript codes, this is more or less it would look like:

Number.equal = function (x, y) {
    if(Number.isNaN(x)) {
        // If x is NaN, return false
        return false;
    }
    if(Number.isNaN(y)) {
        // If y is NaN, return false.
        return false;
    }
    if(x === y) {
        // If x is y, return true
        return true;
    }
    if(1/Number(x) === Infinity && 1/Number(y) === -Infinity) {
        // If x is +0 and y is -0, return true.
        return true;
    }
    if(1/Number(x) === -Infinity && 1/Number(y) === Infinity) {
        // If x is -0 and y is +0, return true
        return true;
    }
    
    // Return false
    return false;
};
Number.equal(30, 30);
Number::sameValue(x, y)

The abstract operation Number::sameValue takes arguments x (a Number) and y (a Number) and returns a Boolean. It performs the following steps when called:

  1. If x is NaN and y is NaN, return true.
  2. If x is +0 and y is -0, return false.
  3. If x is -0 and y is +0, return false.
  4. If x is y, return true.
  5. Return false.

If we translated the steps into Javascript codes, this is more or less it would look like:

Number.sameValue = function (x, y) {
    if(Number.isNaN(x) && Number.isNaN(y)) {
        // If x is NaN and y is NaN, return true
        return true;
    }
    if(1/Number(x) === Infinity && 1/Number(y) ==== -Infinity) {
        // If x is +0 and y is -0, return false
        return false;
    }
    if(1/Number(x) === -Infinity && 1/Number(y) ==== Infinity) {
        // If x is -0 and y is +0, return false
        return false;
    }
    if(Number(x) === Number(y)) {
        // If x is y, return true
        return true;
    }
    
    // Return false
    return false;
};
Number.sameValue(0, -0);
Number::sameValueZero(x, y)

The abstract operation Number::sameValueZero takes arguments x (a Number) and y (a Number) and returns a Boolean. It performs the following steps when called:

  1. If x is NaN and y is NaN, return true.
  2. If x is +0 and y is -0, return true.
  3. If x is -0 and y is +0, return true.
  4. If x is y, return true.
  5. Return false.

If we translated the steps into Javascript codes, this is more or less it would look like:

Number.sameValueZero = function (x, y) {
    if(Number.isNaN(x) && Number.isNaN(y)) {
        // If x is NaN and y is NaN, return true.
        return true;
    }
    if(1/Number(x) === Infinity && 1/Number(y) ==== -Infinity) {
        // If x is +0 and y is -0, return true.
        return true;
    }
    if(1/Number(x) === -Infinity && 1/Number(y) ==== Infinity) {
        // If x is -0 and y is +0, return true.
        return true;
    }
    if(Number(x) === Number(y)) {
        // If x is y, return true
        return true;
    }
    
    // Return false
    return false;
};
Number.sameValueZero(0, -0);
NumberBitwiseOp (op, x, y)

The abstract operation NumberBitwiseOp takes arguments op (&, ^, or |), x (a Number), and y (a Number) and returns an integral Number. It performs the following steps when called:

  1. Let lnum be !ToInt32(x).
  2. Let rnum be !ToInt32(y).
  3. Let lbits be the 32-bit two's complement bit string representing lnum.
  4. Let rbits be the 32-bit two's complement bit string representing rnum.
  5. If op is &, let result be the result of applying the bitwise AND operation to lbits and rbits.
  6. Else if op is ^, let result be the result of applying the bitwise exclusive OR (XOR) operation to lbits and rbits.
  7. Else, op is |. Let result be the result of applying the bitwise inclusive OR operation to lbits and rbits.
  8. Return the Number value for the integer represented by the 32-bit two's complement bit string result.

The !ToInt32(x) just means that we are certain that this call to ToInt32 will never return an exception

If we translated the steps into Javascript codes, this is more or less it would look like:

function NumberBitwiseOp(op, x, y) {
    // Let lnum be ! ToInt32(x)
    let lnum = Number(x);

    // Let rnum be ! ToInt32(y)
    let rnum = Number(y);

    // Let lbits be the 32-bit two's complement bit string representing lnum
    let lbits = lnum;

    // Let rbits be the 32-bit two's complement bit string representing rnum
    let rbits = rnum;
    
    let result;

    if(op == '&') {
        // If op is &, let result be the result of applying the bitwise AND operation to lbits and rbits
        result = lbits & rbits;
    }
    else if(op == '&') {
        // Else if op is ^, let result be the result of applying the bitwise exclusive OR (XOR) operation to lbits
        result = lbits ^ rbits;
    }
    else {
        // Else, op is |. Let result be the result of applying the bitwise inclusive OR operation to lbits and rbits
        result = lbits | rbits;
    }

    // Return the Number value for the integer represented by the 32-bit two's complement bit string result
    return result;
};
Number::bitwiseAND (x, y)

The abstract operation Number::bitwiseAND takes arguments x (a Number) and y (a Number) and returns an integral Number. It performs the following steps when called:

  1. Return NumberBitwiseOp(&, x, y)

If we translated the steps into Javascript codes, this is more or less it would look like:

function NumberBitwiseOp(op, x, y) {
    // Let lnum be ! ToInt32(x)
    let lnum = Number(x);

    // Let rnum be ! ToInt32(y)
    let rnum = Number(y);

    // Let lbits be the 32-bit two's complement bit string representing lnum
    let lbits = lnum;

    // Let rbits be the 32-bit two's complement bit string representing rnum
    let rbits = rnum;
    
    let result;

    if(op == '&') {
        // If op is &, let result be the result of applying the bitwise AND operation to lbits and rbits
        result = lbits & rbits;
    }
    else if(op == '&') {
        // Else if op is ^, let result be the result of applying the bitwise exclusive OR (XOR) operation to lbits
        result = lbits ^ rbits;
    }
    else {
        // Else, op is |. Let result be the result of applying the bitwise inclusive OR operation to lbits and rbits
        result = lbits | rbits;
    }

    // Return the Number value for the integer represented by the 32-bit two's complement bit string result
    return result;
};
Number.bitwiseAND = function(x, y) {
    return NumberBitwiseOp('&', x, y);
}
Number.bitwiseAND(20, 30);
Number::bitwiseXOR (x, y)

The abstract operation Number::bitwiseXOR takes arguments x (a Number) and y (a Number) and returns an integral Number. It performs the following steps when called:

  1. Return NumberBitwiseOp(^, x, y)

If we translated the steps into Javascript codes, this is more or less it would look like:

function NumberBitwiseOp(op, x, y) {
// Let lnum be ! ToInt32(x)
let lnum = Number(x);

// Let rnum be ! ToInt32(y)
let rnum = Number(y);

// Let lbits be the 32-bit two's complement bit string representing lnum
let lbits = lnum;

// Let rbits be the 32-bit two's complement bit string representing rnum
let rbits = rnum;

let result;

if(op == '&') {
// If op is &, let result be the result of applying the bitwise AND operation to lbits and rbits
result = lbits & rbits;
}
else if(op == '&') {
// Else if op is ^, let result be the result of applying the bitwise exclusive OR (XOR) operation to lbits
result = lbits ^ rbits;
}
else {
// Else, op is |. Let result be the result of applying the bitwise inclusive OR operation to lbits and rbits
result = lbits | rbits;
}

// Return the Number value for the integer represented by the 32-bit two's complement bit string result
return result;
};
Number.bitwiseXOR = function(x, y) {
    return NumberBitwiseOp('^', x, y);
}
Number.bitwiseXOR (20, 30);
Number::bitwiseOR (x, y)

The abstract operation Number::bitwiseOR takes arguments x (a Number) and y (a Number) and returns an integral Number. It performs the following steps when called:

  1. Return NumberBitwiseOp(|, x, y)

If we translated the steps into Javascript codes, this is more or less it would look like:

function NumberBitwiseOp(op, x, y) {
    // Let lnum be ! ToInt32(x)
    let lnum = Number(x);

    // Let rnum be ! ToInt32(y)
    let rnum = Number(y);

    // Let lbits be the 32-bit two's complement bit string representing lnum
    let lbits = lnum;

    // Let rbits be the 32-bit two's complement bit string representing rnum
    let rbits = rnum;

    let result;

    if(op == '&') {
    // If op is &, let result be the result of applying the bitwise AND operation to lbits and rbits
    result = lbits & rbits;
    }
    else if(op == '&') {
    // Else if op is ^, let result be the result of applying the bitwise exclusive OR (XOR) operation to lbits
    result = lbits ^ rbits;
    }
    else {
    // Else, op is |. Let result be the result of applying the bitwise inclusive OR operation to lbits and rbits
    result = lbits | rbits;
    }

    // Return the Number value for the integer represented by the 32-bit two's complement bit string result
    return result;
};
Number.bitwiseOR = function(x, y) {
    return NumberBitwiseOp('|', x, y);
}
Number.bitwiseOR (20, 30);
Number::toString (x, radix)

The abstract operation Number::toString takes arguments x (a Number) and radix (an integer in the inclusive interval from 2 to 36) and returns a String. It represents x as a String using a positional numeral system with radix radix. The digits used in the representation of a number using radix r are taken from the first r code units of 0123456789abcdefghijklmnopqrstuvwxyz in order. The representation of numbers with magnitude greater than or equal to 1 never includes leading zeroes. It performs the following steps when called:

  1. If x is NaN, return "NaN".
  2. If x is either +0 or -0, return "0".
  3. If x < -0, return the string-concatenation of "-" and Number::toString(-x, radix).
  4. If x is +∞, return "Infinity".
  5. Let n, k, and s be integers such that $$k ≥ 1$$, $$radix^{k - 1} ≤ s < radix^k$$, $$s × radix^{n - k}$$ is $$x$$, and $$k$$ is as small as possible. Note that k is the number of digits in the representation of s using radix radix, that s is not divisible by radix, and that the least significant digit of s is not necessarily uniquely determined by these criteria.

    In simple words, x is an integer, n is the position of the leading digit of x, with n=0 being the first fraction (0.X), n=1 being the least significant integer position (X.0), n=2 being the "tens" position (X0.0) etc. s is the integer representation that results from stripping all trailing zeroes of x, and k is the number of digits in s.

    Example 1:
    x = 100000000000000000000, would yield s = 1, k = 1, n = 21. Therefore the x passes point 6a and will return "100000000000000000000"

    Example 2:
    x = 10000000000000000000000, would yield s = 1, k = 1, n = 23. Therefore the x passes point 11a and will return "1e+22"

    Example 3:
    x = 0.000003001, would yield s = 3001, k = 4, n = -5. Therefore the x passes point 6c and will return "0.000003001"

    Example 4:
    x = 0.0000003001, would yield s = 3001, k = 4, n = -6. Therefore the x passes point 12 and will return "3.001e-7"

    Example 5:
    x = 100000000.00000003001, would yield s = 10000000000000003001, k = 20, n = 9. Therefore the x passes point 6b and will return "100000000.00000003" since the floating-point numbers in JavaScript can only keep 16 decimal places of precision; beyond that, the value will be changed.

    Example 6:
    x = 1000000000.00000003001, would yield s = 100000000000000003001, k = 21, n = 10. Therefore the x passes point 6b and will return "100000000". It actually returned "100000000.0000000" since the floating-point numbers in JavaScript can only keep 16 decimal places of precision and since Javascript automatically removes the trailing zeros of a floating point number, it returned "100000000".

  6. If radix ≠ 10 or n is in the inclusive interval from -5 to 21, then
    1. If n ≥ k, then
      1. Return the string-concatenation of:
        1. the code units of the k digits of the representation of s using radix radix
        2. n - k occurrences of the code unit 0x0030 (DIGIT ZERO)
    2. Else if n > 0, then
      1. Return the string-concatenation of:
        1. the code units of the most significant n digits of the representation of s using radix radix
        2. the code unit 0x002E (FULL STOP)
        3. the code units of the remaining k - n digits of the representation of s using radix radix
    3. Else,
      1. Assert: n ≤ 0.
      2. Return the string-concatenation of:
        1. the code unit 0x0030 (DIGIT ZERO)
        2. the code unit 0x002E (FULL STOP)
        3. -n occurrences of the code unit 0x0030 (DIGIT ZERO)
        4. the code units of the k digits of the representation of s using radix radix
  7. NOTE: In this case, the input will be represented using scientific E notation, such as 1.2e+3.
  8. Assert: radix is 10.
  9. If n < 0, then
    1. Let exponentSign be the code unit 0x002D (HYPHEN-MINUS).
  10. Else,
    1. Let exponentSign be the code unit 0x002B (PLUS SIGN).
  11. If k = 1, then
    1. Return the string-concatenation of:
      1. the code unit of the single digit of s
      2. the code unit 0x0065 (LATIN SMALL LETTER E)
      3. exponentSign
      4. the code units of the decimal representation of abs(n - 1)
  12. Return the string-concatenation of:
    1. the code unit of the most significant digit of the decimal representation of s
    2. the code unit 0x002E (FULL STOP)
    3. the code units of the remaining k - 1 digits of the decimal representation of s
    4. the code unit 0x0065 (LATIN SMALL LETTER E)
    5. exponentSign
    6. the code units of the decimal representation of abs(n - 1)

If we translated the steps into Javascript codes, this is more or less it would look like:

Number.toString = function (x, radix) {
    if(Number.isNaN(x)) {
        // If x is NaN, return "NaN"
        return "NaN";
    }

    if(x === 0) {
        // If x is either +0 or -0, return "0"
        return "0";
    }
    
    if(x < 0) {
        // If x < -0, return the string-concatenation of "-" and Number::toString(-x, radix)
        return "-" + Number.toString(-x, radix);
    }

    if(x === Infinity) {
        // If x is +∞, return "Infinity".
        return "Infinity";
    }

    let n = 0;
    let k = 0;
    let narray = [];
    let karray = [];
    let whole;
    let fraction;
    
    if(Math.floor(x) === Math.ceil(x)) {
        whole = x + "";
    } else {
        let str = x.toString().split(".");
        whole = str[0];
        fraction = str[1];
    }
    
    let temp = x;
    let numofzero = 0;
    let iszero = true;
    
    while(Math.floor(temp) > 0) {
        n = n + 1;
        narray.push(whole[whole.length - n]);
        
        k = k + 1;
        karray.push(whole[whole.length - n]);
        
        //console.log(whole[whole.length-n])
        if(Math.floor(x) === Math.ceil(x) && whole[whole.length - n] === "0" && iszero) {
            k = k - 1;
            
            karray.pop();
            
            numofzero = numofzero + 1;
        } else {
            iszero = false;
        }
        
        temp = temp / 10;
    }
    
    temp = x;
    iszero = true;
    let i = 0;
    while(Math.ceil(temp) !== Math.floor(temp)) {
        temp = temp * 10;
        
        if(n <= 0 && Math.floor(temp) === 0 && iszero) {
            n = n - 1;
            narray.push(fraction[i]);
        } else {
            k = k + 1;
            iszero = false;
            karray.unshift(fraction[i]);
        }
        i = i + 1;
    }
    
    function numbertobase(number, rad) {
        let wnum;
        let fnum;
        if(Math.floor(number) === Math.ceil(number)) {
            wnum = number;
        } else {
            let str = number.split(".");
            wnum = str[0];
            fnum = str[1];
        }
    
        let numberofdigits = Math.round(Math.log10(Math.pow(2,53)) / Math.log10(rad)) + 1;
        let result = "";
        let zeropads = "";

        while(wnum > 0) {
            let remainder = wnum - Math.floor(wnum / rad) * rad + "";
            
            if (remainder === "10") {
                result = "A" + result;
            } else if (remainder === "11") {
                result = "B" + result;
            } else if (remainder === "12") {
                result = "C" + result;
            } else if (remainder === "13") {
                result = "D" + result;
            } else if (remainder === "14") {
                result = "E" + result;
            } else if (remainder === "15") {
                result = "F" + result;
            } else if (remainder === "16") {
                result = "G" + result;
            } else if (remainder === "17") {
                result = "H" + result;
            } else if (remainder === "18") {
                result = "I" + result;
            } else if (remainder === "19") {
                result = "J" + result;
            } else if (remainder === "20") {
                result = "K" + result;
            } else if (remainder === "21") {
                result = "L" + result;
            } else if (remainder === "22") {
                result = "M" + result;
            } else if (remainder === "23") {
                result = "N" + result;
            } else if (remainder === "24") {
                result = "O" + result;
            } else if (remainder === "25") {
                result = "P" + result;
            } else if (remainder === "26") {
                result = "Q" + result;
            } else if (remainder === "27") {
                result = "R" + result;
            } else if (remainder === "28") {
                result = "S" + result;
            } else if (remainder === "29") {
                result = "T" + result;
            } else if (remainder === "30") {
                result = "U" + result;
            } else if (remainder === "31") {
                result = "V" + result;
            } else if (remainder === "32") {
                result = "W" + result;
            } else if (remainder === "33") {
                result = "X" + result;
            } else if (remainder === "34") {
                result = "Y" + result;
            } else if (remainder === "35") {
                result = "Z" + result;
            } else {
                result = remainder + result;
            }
            numberofdigits = numberofdigits - 1;
            
            wnum = Math.floor(wnum / rad);
        }
        
        if(Math.ceil(number) !== Math.floor(number)) {
            const factor = Math.pow(10, fnum.length)
            fnum = "1." + fnum;
            
            if(fnum > 0) {
                if(result === "") {
                    result = "0.";
                } else {
                    result = result + ".";
                }
            }
            
            while(fnum > 0) {
                fnum = (Math.round(fnum * rad * factor) / factor) + "";
                str = fnum.split(".");
                let num = str[0] - rad + "";
                fnum = "1." + str[1];
                
                if (num > 0) {
                    result = result + zeropads;
                    zeropads = "";
                }
                
                if (num === "10") {
                    result = result + "A";
                } else if (num === "11") {
                    result = result + "B";
                } else if (num === "12") {
                    result = result + "C";
                } else if (num === "13") {
                    result = result + "D";
                } else if (num === "14") {
                    result = result + "E";
                } else if (num === "15") {
                    result = result + "F";
                } else if (num === "16") {
                    result = result + "G";
                } else if (num === "17") {
                    result = result + "H";
                } else if (num === "18") {
                    result = result + "I";
                } else if (num === "19") {
                    result = result + "J";
                } else if (num === "20") {
                    result = result + "K";
                } else if (num === "21") {
                    result = result + "L";
                } else if (num === "22") {
                    result = result + "M";
                } else if (num === "23") {
                    result = result + "N";
                } else if (num === "24") {
                    result = result + "O";
                } else if (num === "25") {
                    result = result + "P";
                } else if (num === "26") {
                    result = result + "Q";
                } else if (num === "27") {
                    result = result + "R";
                } else if (num === "28") {
                    result = result + "S";
                } else if (num === "29") {
                    result = result + "T";
                } else if (num === "30") {
                    result = result + "U";
                } else if (num === "31") {
                    result = result + "V";
                } else if (num === "32") {
                    result = result + "W";
                } else if (num === "33") {
                    result = result + "X";
                } else if (num === "34") {
                    result = result + "Y";
                } else if (num === "35") {
                    result = result + "Z";
                } else if (num === "0") {
                    zeropads = zeropads + "0";
                } else {
                    result = result + num;
                }
                
                numberofdigits = numberofdigits - 1;
                
                if(numberofdigits === 0) {
                    break;
                }
                
            }
        } 
        
        return result;
    }
    //let s = x / 10 ** (n-k);

    if(radix !== 10 || (n >= -5 && n <= 21)) {
        // If radix ≠ 10 or n is in the inclusive interval from -5 to 21, then

        if(n >= k) {
            // If n ≥ k, then
            // Return the string-concatenation of: 
            // the code units of the k digits of the representation of s using radix radix
            // n - k occurrences of the code unit 0x0030 (DIGIT ZERO)
            
            return numbertobase(karray.reverse().join("") + narray.slice(0, n - k).reverse().join(""), radix);
        } else if(n > 0) {
            // Else if n > 0, then
            // Return the string-concatenation of:
            // the code units of the most significant n digits of the representation of s using radix radix
            // the code unit 0x002E (FULL STOP)
            // the code units of the remaining k - n digits of the representation of s using radix radix
            
            return numbertobase(narray.reverse().join("") + "." +  karray.slice(0, k - n).reverse().join(""), radix);
        } else {
            // Else n ≤ 0
            // Return the string-concatenation of:
            // the code unit 0x0030 (DIGIT ZERO)
            // the code unit 0x002E (FULL STOP)
            // -n occurrences of the code unit 0x0030 (DIGIT ZERO)
            // the code units of the k digits of the representation of s using radix radix
            
            return numbertobase("0" + "." + narray.reverse().join("") + karray.reverse().join(""), radix);
        }
    }

    let exponentSign;
    // radix is 10
    if(n < 0) {
        // If n < 0, then
        // Let exponentSign be the code unit 0x002D (HYPHEN-MINUS)
        exponentSign = "-";
    } else {
        // Else
        // Let exponentSign be the code unit 0x002B (PLUS SIGN)
        exponentSign = "+";
    }

    if(k === 1) {
        // If k = 1, then
        // the code unit of the single digit of s
        // the code unit 0x0065 (LATIN SMALL LETTER E)
        // exponentSign
        // the code units of the decimal representation of abs(n - 1)
        return karray.reverse().join("") + "e" + exponentSign + Math.abs(n - 1);
    }
    
    // Return the string-concatenation of:
    // the code unit of the most significant digit of the decimal representation of s
    // the code unit 0x002E (FULL STOP)
    // the code units of the remaining k - 1 digits of the decimal representation of s
    // the code unit 0x0065 (LATIN SMALL LETTER E)
    // exponentSign
    // the code units of the decimal representation of abs(n - 1)

    return karray[karray.length - 1] + "." + karray.slice(0, karray.length - 1).reverse().join("") + "e" + exponentSign + Math.abs(n - 1);
};
Number.toString(100000000000000000000, 10);
// "100000000000000000000"
Number.toString(100000000000000000000, 16);
// "56BC75E2D63100000"
Number.toString(0.000003001, 10);
// "0.000003001"
Number.toString(0.000003001, 16);
// "0.0000325932651B"
Number.toString(100000000.00000003001, 10);
// "100000000.00000003"
Number.toString(100000000.00000003001, 16);
// "5f5e100.0000008"