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:
- If
x
isNaN
, returnNaN
. - Return the result of negating
x
; that is, compute aNumber
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:
- Let
oldValue
be!ToInt32(x)
- 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:
- If
exponent
isNaN
, returnNaN
. - If
exponent
is either +0 or -0, return1
. - If
base
isNaN
, returnNaN
. - If
base
is +∞, then
- If
exponent
> +0, return +∞. Otherwise, return +0
- If
- If
base
is -∞, then
- If
exponent
> +0, then
- If
exponent
is an odd integral Number, return -∞. Otherwise, return +∞.
- If
- Else
- If
exponent
is an odd integral Number, return -0. Otherwise, return +0.
- If
- If
- If
base
is +0, then
- If
exponent
> +0, return +0. Otherwise, return +∞.
- If
- If
base
is -0, then
- If
exponent
> +0, return +0. Otherwise, return +∞.
- If
exponent
is an odd integral Number, return -0. Otherwise, return +0.
- If
- Else,
- If
exponent
is an odd integral Number, return -∞. Otherwise, return +∞.
- If
- If
-
Assert:
base
is finite and is neither +0 nor -0. - If
exponent
is +∞, then
- If
abs(base)
> 1, return +∞. - If
abs(base)
= 1, returnNaN
. - If
abs(base)
< 1, return +0.
- If
- If
exponent
is -∞, then
- If
abs(base)
> 1, return +0. - If
abs(base)
= 1, returnNaN
. - If
abs(base)
< 1, return +∞.
- If
- Assert:
exponent
is finite and is neither +0 nor -0. - If
base
< -0 andexponent
is not an integral Number, returnNaN
. - Return an implementation-approximated Number value representing the result of raising
base
to theexponent
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:
- If
x
isNaN
ory
isNaN
, returnNaN
. - If
x
is either +∞ or -∞, then
- If
y
is either +0 or -0, returnNaN
. - If
y
> +0, returnx
. - Return
-x
.
- If
- If
y
is either +∞ or -∞, then
- If
x
is either +0 or -0, returnNaN
. - If
x
> +0, returny
. - Return
-y
.
- If
- If x is -0, then
- If
y
is -0 ory
< -0, return +0. - Else, return -0.
- If
- If y is -0, then
- If
x
< -0, return +0. - Else, return -0.
- If
- 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:
- If
x
isNaN
ory
isNaN
, returnNaN
. - If
x
is either +∞ or -∞, then
- If
y
is either +∞ or -∞, returnNaN
. - If
y
is +0 ory
> +0, returnx
. - Return
-x
.
- If
- If
y
is +∞, then
- If
x
is +0 orx
> +0, return +0. Otherwise, return -0.
- If
- If
y
is -∞, then
-
If
x
is +0 orx
> +0, return -0. Otherwise, return +0. - If
x
is either +0 or -0, then
- If
y
is either +0 or -0, returnNaN
. - If
y
> +0, returnx
. - Return
-x
.
- If
- If
y
is +0, then
- If
x
> +0, return +∞. Otherwise, return -∞.
- If
- If
y
is -0, then
- If
x
> +0, return -∞. Otherwise, return +∞. - 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:
- If
n
isNaN
ord
isNaN
, returnNaN
. - If
n
is either +∞ or -∞, returnNaN
. - If
d
is either +∞ or -∞, returnn
. - If
d
is either +0 or -0, returnNaN
. - If
n
is either +0 or -0, returnn
. - Assert:
n
andd
are finite and non-zero. - Let
quotient
ben / d
. - Let
q
betruncate(quotient)
. - Let
r
ben - (d × q)
. - If
r
= 0 andn
< -0, return -0. - 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:
- If
x
isNaN
ory
isNaN
, returnNaN
. - If
x
is +∞ andy
is -∞, returnNaN
. - If
x
is -∞ andy
is +∞, returnNaN
. - If
x
is either +∞ or -∞, returnx
. - If
y
is either +∞ or -∞, returny
. - Assert:
x
andy
are both finite. - If
x
is -0 andy
is -0, return -0. - 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:
- 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:
- Let
lnum
be!ToInt32(x)
. - Let
rnum
be!ToUint32(y)
. - Let
shiftCount
bernum modulo 32
. - Return the result of left shifting
lnum
byshiftCount
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:
- Let
lnum
be!ToInt32(x)
. - Let
rnum
be!ToUint32(y)
. - Let
shiftCount
bernum modulo 32
. - Return the result of performing a sign-extending right shift of
lnum
byshiftCount
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:
- Let
lnum
be!ToUint32(x)
. - Let
rnum
be!ToUint32(y)
. - Let
shiftCount
bernum modulo 32
. - Return the result of performing a zero-filling right shift of
lnum
byshiftCount
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:
- If
x
isNaN
, returnundefined
. - If
y
isNaN
, returnundefined
. - If
x
isy
, returnfalse
. - If
x
is +0 andy
is -0, returnfalse
. - If
x
is -0 andy
is +0, returnfalse
. - If
x
is +∞, returnfalse
. - If
y
is +∞, returntrue
. - If
y
is -∞, returnfalse
. - If
x
is -∞, returntrue
. - Assert:
x
andy
are finite and non-zero. - If
x
<y
, returntrue
. Otherwise, returnfalse
.
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:
- If
x
isNaN
, returnfalse
. - If
y
isNaN
, returnfalse
. - If
x
isy
, returntrue
. - If
x
is +0 andy
is -0, returntrue
. - If
x
is -0 andy
is +0, returntrue
. - 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:
- If
x
isNaN
andy
isNaN
, returntrue
. - If
x
is +0 andy
is -0, returnfalse
. - If
x
is -0 andy
is +0, returnfalse
. - If
x
isy
, returntrue
. - 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:
- If
x
isNaN
andy
isNaN
, returntrue
. - If
x
is +0 andy
is -0, returntrue
. - If
x
is -0 andy
is +0, returntrue
. - If
x
isy
, returntrue
. - 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:
- Let
lnum
be!ToInt32(x)
. - Let
rnum
be!ToInt32(y)
. - Let
lbits
be the 32-bit two's complement bit string representinglnum
. - Let
rbits
be the 32-bit two's complement bit string representingrnum
. - If
op
is&
, letresult
be the result of applying the bitwise AND operation tolbits
andrbits
. - Else if
op
is^
, letresult
be the result of applying the bitwise exclusive OR (XOR) operation tolbits
andrbits
. - Else,
op
is|
. Letresult
be the result of applying the bitwise inclusive OR operation tolbits
andrbits
. - 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:
- 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:
- 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:
- 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:
- If
x
isNaN
, return"NaN"
. - If
x
is either +0 or -0, return"0"
. - If
x
< -0, return the string-concatenation of"-"
andNumber::toString(-x, radix)
. - If
x
is +∞, return"Infinity"
. - Let
n
,k
, ands
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 thatk
is the number of digits in the representation ofs
using radixradix
, thats
is not divisible byradix
, and that the least significant digit ofs
is not necessarily uniquely determined by these criteria.
In simple words,x
is an integer,n
is the position of the leading digit ofx
, 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 ofx
, andk
is the number of digits ins
.
Example 1:
x
= 100000000000000000000, would yields
= 1,k
= 1,n
= 21. Therefore thex
passes point 6a and will return "100000000000000000000"
Example 2:
x
= 10000000000000000000000, would yields
= 1,k
= 1,n
= 23. Therefore thex
passes point 11a and will return "1e+22"
Example 3:
x
= 0.000003001, would yields
= 3001,k
= 4,n
= -5. Therefore thex
passes point 6c and will return "0.000003001"
Example 4:
x
= 0.0000003001, would yields
= 3001,k
= 4,n
= -6. Therefore thex
passes point 12 and will return "3.001e-7"
Example 5:
x
= 100000000.00000003001, would yields
= 10000000000000003001,k
= 20,n
= 9. Therefore thex
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 yields
= 100000000000000003001,k
= 21,n
= 10. Therefore thex
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".
- If radix ≠ 10 or n is in the inclusive interval from -5 to 21, then
- 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 the string-concatenation of:
- 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 the string-concatenation of:
- Else,
- Assert: 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
- If n ≥ k, then
- NOTE: In this case, the input will be represented using scientific E notation, such as 1.2e+3.
- Assert: radix is 10.
- If n < 0, then
- Let exponentSign be the code unit 0x002D (HYPHEN-MINUS).
- Else,
- Let exponentSign be the code unit 0x002B (PLUS SIGN).
- If k = 1, then
- Return the string-concatenation of:
- 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 the string-concatenation of:
- 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)
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"