How to create a 32-bit integer from eight (8) 4-bit integers?
Let's say I have a max 32-bit integer -
const a =
((2 ** 32) - 1)
const b =
parseInt("11111111111111111111111111111111", 2) // 32 bits, each is a one!
console.log(a === b) // true
console.log(a.toString(2))
// 11111111111111111111111111111111 (32 ones)
console.log(b.toString(2))
// 11111111111111111111111111111111 (32 ones)
So far so good. But now let's say I want to make a 32-bit number using eight (8) 4-bit numbers. The idea is simple: shift (<<
) each 4-bit sequence into position and add (+
) them together -
const make = ([ bit, ...more ], e = 0) =>
bit === undefined
? 0
: (bit << e) + make (more, e + 4)
const print = n =>
console.log(n.toString(2))
// 4 bits
print(make([ 15 ])) // 1111
// 8 bits
print(make([ 15, 15 ])) // 11111111
// 12 bits
print(make([ 15, 15, 15 ])) // 111111111111
// 16 bits
print(make([ 15, 15, 15, 15 ])) // 1111111111111111
// 20 bits
print(make([ 15, 15, 15, 15, 15 ])) // 11111111111111111111
// 24 bits
print(make([ 15, 15, 15, 15, 15, 15 ])) // 111111111111111111111111
// 28 bits
print(make([ 15, 15, 15, 15, 15, 15, 15 ])) // 1111111111111111111111111111
// almost there ... now 32 bits
print(make([ 15, 15, 15, 15, 15, 15, 15, 15 ])) // -1 :(
I'm getting -1
but the expected result is 32-bits of all ones, or 11111111111111111111111111111111
.
Worse, if I start with the expected outcome and work my way backwards, I get the expected result -
const c =
`11111111111111111111111111111111`
const d =
parseInt(c, 2)
console.log(d) // 4294967295
console.log(d.toString(2) === c) // true
I tried debugging my make function to ensure there wasn't an obvious problem -
const make = ([ bit, ...more ], e = 0) =>
bit === undefined
? `0`
: `(${bit} << ${e}) + ` + make (more, e + 4)
console.log(make([ 15, 15, 15, 15, 15, 15, 15, 15 ]))
// (15 << 0) + (15 << 4) + (15 << 8) + (15 << 12) + (15 << 16) + (15 << 20) + (15 << 24) + (15 << 28) + 0
The formula looks like it checks out. I thought maybe it was something to do with +
and switched to bitwise or (|
) which should effectively do the same thing here -
const a =
parseInt("1111",2)
const b =
(a << 0) | (a << 4)
console.log(b.toString(2)) // 11111111
const c =
b | (a << 8)
console.log(c.toString(2)) // 111111111111
However, I get the same bug with my make
function when attempting to combine all eight (8) numbers -
const make = ([ bit, ...more ], e = 0) =>
bit === undefined
? 0
: (bit << e) | make (more, e + 4)
const print = n =>
console.log(n.toString(2))
print(make([ 15, 15, 15, 15, 15, 15, 15 ])) // 1111111111111111111111111111 (28 bits)
print(make([ 15, 15, 15, 15, 15, 15, 15, 15 ])) // -1 :(
What gives?
The goal is to convert eight (8) 4-bit integers into a single 32-bit integer using JavaScript - this is just my attempt. I'm curious where my function is breaking, but I'm open to alternative solutions.
I'd like to avoid converting each 4-bit integer to a binary string, mashing the binary strings together, then parsing the binary string into a single int. A numeric solution is preferred.
javascript twos-complement base-conversion
add a comment |
Let's say I have a max 32-bit integer -
const a =
((2 ** 32) - 1)
const b =
parseInt("11111111111111111111111111111111", 2) // 32 bits, each is a one!
console.log(a === b) // true
console.log(a.toString(2))
// 11111111111111111111111111111111 (32 ones)
console.log(b.toString(2))
// 11111111111111111111111111111111 (32 ones)
So far so good. But now let's say I want to make a 32-bit number using eight (8) 4-bit numbers. The idea is simple: shift (<<
) each 4-bit sequence into position and add (+
) them together -
const make = ([ bit, ...more ], e = 0) =>
bit === undefined
? 0
: (bit << e) + make (more, e + 4)
const print = n =>
console.log(n.toString(2))
// 4 bits
print(make([ 15 ])) // 1111
// 8 bits
print(make([ 15, 15 ])) // 11111111
// 12 bits
print(make([ 15, 15, 15 ])) // 111111111111
// 16 bits
print(make([ 15, 15, 15, 15 ])) // 1111111111111111
// 20 bits
print(make([ 15, 15, 15, 15, 15 ])) // 11111111111111111111
// 24 bits
print(make([ 15, 15, 15, 15, 15, 15 ])) // 111111111111111111111111
// 28 bits
print(make([ 15, 15, 15, 15, 15, 15, 15 ])) // 1111111111111111111111111111
// almost there ... now 32 bits
print(make([ 15, 15, 15, 15, 15, 15, 15, 15 ])) // -1 :(
I'm getting -1
but the expected result is 32-bits of all ones, or 11111111111111111111111111111111
.
Worse, if I start with the expected outcome and work my way backwards, I get the expected result -
const c =
`11111111111111111111111111111111`
const d =
parseInt(c, 2)
console.log(d) // 4294967295
console.log(d.toString(2) === c) // true
I tried debugging my make function to ensure there wasn't an obvious problem -
const make = ([ bit, ...more ], e = 0) =>
bit === undefined
? `0`
: `(${bit} << ${e}) + ` + make (more, e + 4)
console.log(make([ 15, 15, 15, 15, 15, 15, 15, 15 ]))
// (15 << 0) + (15 << 4) + (15 << 8) + (15 << 12) + (15 << 16) + (15 << 20) + (15 << 24) + (15 << 28) + 0
The formula looks like it checks out. I thought maybe it was something to do with +
and switched to bitwise or (|
) which should effectively do the same thing here -
const a =
parseInt("1111",2)
const b =
(a << 0) | (a << 4)
console.log(b.toString(2)) // 11111111
const c =
b | (a << 8)
console.log(c.toString(2)) // 111111111111
However, I get the same bug with my make
function when attempting to combine all eight (8) numbers -
const make = ([ bit, ...more ], e = 0) =>
bit === undefined
? 0
: (bit << e) | make (more, e + 4)
const print = n =>
console.log(n.toString(2))
print(make([ 15, 15, 15, 15, 15, 15, 15 ])) // 1111111111111111111111111111 (28 bits)
print(make([ 15, 15, 15, 15, 15, 15, 15, 15 ])) // -1 :(
What gives?
The goal is to convert eight (8) 4-bit integers into a single 32-bit integer using JavaScript - this is just my attempt. I'm curious where my function is breaking, but I'm open to alternative solutions.
I'd like to avoid converting each 4-bit integer to a binary string, mashing the binary strings together, then parsing the binary string into a single int. A numeric solution is preferred.
javascript twos-complement base-conversion
1
It looks like bitwise operators says "The numbers-2147483648
and2147483647
are the minimum and the maximum integers representable through a 32-bit signed number." Indeed(15 << 28)
lies beyond this range, however JavaScript's MAX_SAFE_INTEGER supports up to 53 bits. Is there a safe and reliable way to use bitwise operators on larger-than-32-bit numbers?
– user633183
Mar 28 at 6:10
Is the signedness really unacceptable? They're the same bits after all, just slightly a different interpretation
– harold
Mar 28 at 11:00
add a comment |
Let's say I have a max 32-bit integer -
const a =
((2 ** 32) - 1)
const b =
parseInt("11111111111111111111111111111111", 2) // 32 bits, each is a one!
console.log(a === b) // true
console.log(a.toString(2))
// 11111111111111111111111111111111 (32 ones)
console.log(b.toString(2))
// 11111111111111111111111111111111 (32 ones)
So far so good. But now let's say I want to make a 32-bit number using eight (8) 4-bit numbers. The idea is simple: shift (<<
) each 4-bit sequence into position and add (+
) them together -
const make = ([ bit, ...more ], e = 0) =>
bit === undefined
? 0
: (bit << e) + make (more, e + 4)
const print = n =>
console.log(n.toString(2))
// 4 bits
print(make([ 15 ])) // 1111
// 8 bits
print(make([ 15, 15 ])) // 11111111
// 12 bits
print(make([ 15, 15, 15 ])) // 111111111111
// 16 bits
print(make([ 15, 15, 15, 15 ])) // 1111111111111111
// 20 bits
print(make([ 15, 15, 15, 15, 15 ])) // 11111111111111111111
// 24 bits
print(make([ 15, 15, 15, 15, 15, 15 ])) // 111111111111111111111111
// 28 bits
print(make([ 15, 15, 15, 15, 15, 15, 15 ])) // 1111111111111111111111111111
// almost there ... now 32 bits
print(make([ 15, 15, 15, 15, 15, 15, 15, 15 ])) // -1 :(
I'm getting -1
but the expected result is 32-bits of all ones, or 11111111111111111111111111111111
.
Worse, if I start with the expected outcome and work my way backwards, I get the expected result -
const c =
`11111111111111111111111111111111`
const d =
parseInt(c, 2)
console.log(d) // 4294967295
console.log(d.toString(2) === c) // true
I tried debugging my make function to ensure there wasn't an obvious problem -
const make = ([ bit, ...more ], e = 0) =>
bit === undefined
? `0`
: `(${bit} << ${e}) + ` + make (more, e + 4)
console.log(make([ 15, 15, 15, 15, 15, 15, 15, 15 ]))
// (15 << 0) + (15 << 4) + (15 << 8) + (15 << 12) + (15 << 16) + (15 << 20) + (15 << 24) + (15 << 28) + 0
The formula looks like it checks out. I thought maybe it was something to do with +
and switched to bitwise or (|
) which should effectively do the same thing here -
const a =
parseInt("1111",2)
const b =
(a << 0) | (a << 4)
console.log(b.toString(2)) // 11111111
const c =
b | (a << 8)
console.log(c.toString(2)) // 111111111111
However, I get the same bug with my make
function when attempting to combine all eight (8) numbers -
const make = ([ bit, ...more ], e = 0) =>
bit === undefined
? 0
: (bit << e) | make (more, e + 4)
const print = n =>
console.log(n.toString(2))
print(make([ 15, 15, 15, 15, 15, 15, 15 ])) // 1111111111111111111111111111 (28 bits)
print(make([ 15, 15, 15, 15, 15, 15, 15, 15 ])) // -1 :(
What gives?
The goal is to convert eight (8) 4-bit integers into a single 32-bit integer using JavaScript - this is just my attempt. I'm curious where my function is breaking, but I'm open to alternative solutions.
I'd like to avoid converting each 4-bit integer to a binary string, mashing the binary strings together, then parsing the binary string into a single int. A numeric solution is preferred.
javascript twos-complement base-conversion
Let's say I have a max 32-bit integer -
const a =
((2 ** 32) - 1)
const b =
parseInt("11111111111111111111111111111111", 2) // 32 bits, each is a one!
console.log(a === b) // true
console.log(a.toString(2))
// 11111111111111111111111111111111 (32 ones)
console.log(b.toString(2))
// 11111111111111111111111111111111 (32 ones)
So far so good. But now let's say I want to make a 32-bit number using eight (8) 4-bit numbers. The idea is simple: shift (<<
) each 4-bit sequence into position and add (+
) them together -
const make = ([ bit, ...more ], e = 0) =>
bit === undefined
? 0
: (bit << e) + make (more, e + 4)
const print = n =>
console.log(n.toString(2))
// 4 bits
print(make([ 15 ])) // 1111
// 8 bits
print(make([ 15, 15 ])) // 11111111
// 12 bits
print(make([ 15, 15, 15 ])) // 111111111111
// 16 bits
print(make([ 15, 15, 15, 15 ])) // 1111111111111111
// 20 bits
print(make([ 15, 15, 15, 15, 15 ])) // 11111111111111111111
// 24 bits
print(make([ 15, 15, 15, 15, 15, 15 ])) // 111111111111111111111111
// 28 bits
print(make([ 15, 15, 15, 15, 15, 15, 15 ])) // 1111111111111111111111111111
// almost there ... now 32 bits
print(make([ 15, 15, 15, 15, 15, 15, 15, 15 ])) // -1 :(
I'm getting -1
but the expected result is 32-bits of all ones, or 11111111111111111111111111111111
.
Worse, if I start with the expected outcome and work my way backwards, I get the expected result -
const c =
`11111111111111111111111111111111`
const d =
parseInt(c, 2)
console.log(d) // 4294967295
console.log(d.toString(2) === c) // true
I tried debugging my make function to ensure there wasn't an obvious problem -
const make = ([ bit, ...more ], e = 0) =>
bit === undefined
? `0`
: `(${bit} << ${e}) + ` + make (more, e + 4)
console.log(make([ 15, 15, 15, 15, 15, 15, 15, 15 ]))
// (15 << 0) + (15 << 4) + (15 << 8) + (15 << 12) + (15 << 16) + (15 << 20) + (15 << 24) + (15 << 28) + 0
The formula looks like it checks out. I thought maybe it was something to do with +
and switched to bitwise or (|
) which should effectively do the same thing here -
const a =
parseInt("1111",2)
const b =
(a << 0) | (a << 4)
console.log(b.toString(2)) // 11111111
const c =
b | (a << 8)
console.log(c.toString(2)) // 111111111111
However, I get the same bug with my make
function when attempting to combine all eight (8) numbers -
const make = ([ bit, ...more ], e = 0) =>
bit === undefined
? 0
: (bit << e) | make (more, e + 4)
const print = n =>
console.log(n.toString(2))
print(make([ 15, 15, 15, 15, 15, 15, 15 ])) // 1111111111111111111111111111 (28 bits)
print(make([ 15, 15, 15, 15, 15, 15, 15, 15 ])) // -1 :(
What gives?
The goal is to convert eight (8) 4-bit integers into a single 32-bit integer using JavaScript - this is just my attempt. I'm curious where my function is breaking, but I'm open to alternative solutions.
I'd like to avoid converting each 4-bit integer to a binary string, mashing the binary strings together, then parsing the binary string into a single int. A numeric solution is preferred.
const a =
((2 ** 32) - 1)
const b =
parseInt("11111111111111111111111111111111", 2) // 32 bits, each is a one!
console.log(a === b) // true
console.log(a.toString(2))
// 11111111111111111111111111111111 (32 ones)
console.log(b.toString(2))
// 11111111111111111111111111111111 (32 ones)
const a =
((2 ** 32) - 1)
const b =
parseInt("11111111111111111111111111111111", 2) // 32 bits, each is a one!
console.log(a === b) // true
console.log(a.toString(2))
// 11111111111111111111111111111111 (32 ones)
console.log(b.toString(2))
// 11111111111111111111111111111111 (32 ones)
const make = ([ bit, ...more ], e = 0) =>
bit === undefined
? 0
: (bit << e) + make (more, e + 4)
const print = n =>
console.log(n.toString(2))
// 4 bits
print(make([ 15 ])) // 1111
// 8 bits
print(make([ 15, 15 ])) // 11111111
// 12 bits
print(make([ 15, 15, 15 ])) // 111111111111
// 16 bits
print(make([ 15, 15, 15, 15 ])) // 1111111111111111
// 20 bits
print(make([ 15, 15, 15, 15, 15 ])) // 11111111111111111111
// 24 bits
print(make([ 15, 15, 15, 15, 15, 15 ])) // 111111111111111111111111
// 28 bits
print(make([ 15, 15, 15, 15, 15, 15, 15 ])) // 1111111111111111111111111111
// almost there ... now 32 bits
print(make([ 15, 15, 15, 15, 15, 15, 15, 15 ])) // -1 :(
const make = ([ bit, ...more ], e = 0) =>
bit === undefined
? 0
: (bit << e) + make (more, e + 4)
const print = n =>
console.log(n.toString(2))
// 4 bits
print(make([ 15 ])) // 1111
// 8 bits
print(make([ 15, 15 ])) // 11111111
// 12 bits
print(make([ 15, 15, 15 ])) // 111111111111
// 16 bits
print(make([ 15, 15, 15, 15 ])) // 1111111111111111
// 20 bits
print(make([ 15, 15, 15, 15, 15 ])) // 11111111111111111111
// 24 bits
print(make([ 15, 15, 15, 15, 15, 15 ])) // 111111111111111111111111
// 28 bits
print(make([ 15, 15, 15, 15, 15, 15, 15 ])) // 1111111111111111111111111111
// almost there ... now 32 bits
print(make([ 15, 15, 15, 15, 15, 15, 15, 15 ])) // -1 :(
const c =
`11111111111111111111111111111111`
const d =
parseInt(c, 2)
console.log(d) // 4294967295
console.log(d.toString(2) === c) // true
const c =
`11111111111111111111111111111111`
const d =
parseInt(c, 2)
console.log(d) // 4294967295
console.log(d.toString(2) === c) // true
const make = ([ bit, ...more ], e = 0) =>
bit === undefined
? `0`
: `(${bit} << ${e}) + ` + make (more, e + 4)
console.log(make([ 15, 15, 15, 15, 15, 15, 15, 15 ]))
// (15 << 0) + (15 << 4) + (15 << 8) + (15 << 12) + (15 << 16) + (15 << 20) + (15 << 24) + (15 << 28) + 0
const make = ([ bit, ...more ], e = 0) =>
bit === undefined
? `0`
: `(${bit} << ${e}) + ` + make (more, e + 4)
console.log(make([ 15, 15, 15, 15, 15, 15, 15, 15 ]))
// (15 << 0) + (15 << 4) + (15 << 8) + (15 << 12) + (15 << 16) + (15 << 20) + (15 << 24) + (15 << 28) + 0
const a =
parseInt("1111",2)
const b =
(a << 0) | (a << 4)
console.log(b.toString(2)) // 11111111
const c =
b | (a << 8)
console.log(c.toString(2)) // 111111111111
const a =
parseInt("1111",2)
const b =
(a << 0) | (a << 4)
console.log(b.toString(2)) // 11111111
const c =
b | (a << 8)
console.log(c.toString(2)) // 111111111111
const make = ([ bit, ...more ], e = 0) =>
bit === undefined
? 0
: (bit << e) | make (more, e + 4)
const print = n =>
console.log(n.toString(2))
print(make([ 15, 15, 15, 15, 15, 15, 15 ])) // 1111111111111111111111111111 (28 bits)
print(make([ 15, 15, 15, 15, 15, 15, 15, 15 ])) // -1 :(
const make = ([ bit, ...more ], e = 0) =>
bit === undefined
? 0
: (bit << e) | make (more, e + 4)
const print = n =>
console.log(n.toString(2))
print(make([ 15, 15, 15, 15, 15, 15, 15 ])) // 1111111111111111111111111111 (28 bits)
print(make([ 15, 15, 15, 15, 15, 15, 15, 15 ])) // -1 :(
javascript twos-complement base-conversion
javascript twos-complement base-conversion
asked Mar 28 at 5:56
user633183user633183
71.9k21143184
71.9k21143184
1
It looks like bitwise operators says "The numbers-2147483648
and2147483647
are the minimum and the maximum integers representable through a 32-bit signed number." Indeed(15 << 28)
lies beyond this range, however JavaScript's MAX_SAFE_INTEGER supports up to 53 bits. Is there a safe and reliable way to use bitwise operators on larger-than-32-bit numbers?
– user633183
Mar 28 at 6:10
Is the signedness really unacceptable? They're the same bits after all, just slightly a different interpretation
– harold
Mar 28 at 11:00
add a comment |
1
It looks like bitwise operators says "The numbers-2147483648
and2147483647
are the minimum and the maximum integers representable through a 32-bit signed number." Indeed(15 << 28)
lies beyond this range, however JavaScript's MAX_SAFE_INTEGER supports up to 53 bits. Is there a safe and reliable way to use bitwise operators on larger-than-32-bit numbers?
– user633183
Mar 28 at 6:10
Is the signedness really unacceptable? They're the same bits after all, just slightly a different interpretation
– harold
Mar 28 at 11:00
1
1
It looks like bitwise operators says "The numbers
-2147483648
and 2147483647
are the minimum and the maximum integers representable through a 32-bit signed number." Indeed (15 << 28)
lies beyond this range, however JavaScript's MAX_SAFE_INTEGER supports up to 53 bits. Is there a safe and reliable way to use bitwise operators on larger-than-32-bit numbers?– user633183
Mar 28 at 6:10
It looks like bitwise operators says "The numbers
-2147483648
and 2147483647
are the minimum and the maximum integers representable through a 32-bit signed number." Indeed (15 << 28)
lies beyond this range, however JavaScript's MAX_SAFE_INTEGER supports up to 53 bits. Is there a safe and reliable way to use bitwise operators on larger-than-32-bit numbers?– user633183
Mar 28 at 6:10
Is the signedness really unacceptable? They're the same bits after all, just slightly a different interpretation
– harold
Mar 28 at 11:00
Is the signedness really unacceptable? They're the same bits after all, just slightly a different interpretation
– harold
Mar 28 at 11:00
add a comment |
1 Answer
1
active
oldest
votes
The bitwise operators will result in a signed 32 bit number, meaning that if the bit at position 31 (counting from the least significant bit at the right, which is bit 0) is 1, the number will be negative.
To avoid this from happening, use other operators than <<
or |
, which both result in a signed 32-bit number. For instance:
(bit * 2**e) + make (more, e + 4)
Forcing unsigned 32-bit
Bit shifting operators are designed to force the result into the signed 32-bit range, at least that is claimed on mdn (at the time of writing):
The operands of all bitwise operators are converted to signed 32-bit integers
This is in fact not entirely true. The >>>
operator is an exception to this. EcmaScript 2015, section 12.5.8.1 states that the operands are mapped to unsigned 32 bit before shifting in the 0 bits. So even if you would shift zero bits, you'd see that effect.
You would only have to apply it once to the final value, like for instance in your print
function:
console.log((n>>>0).toString(2))
BigInt solution
If you need even more than 32 bits, and your JavaScript engine supports BigInt like some already do, then use BigInts for the operands involved in the bitwise operators -- these will then not use the 32-bit signed number wrapping (notice the n
suffixes):
const make = ([ bit, ...more ], e = 0n) =>
bit === undefined
? 0n
: (bit << e) + make (more, e + 4n)
const print = n =>
console.log(n.toString(2))
// Test
for (let i=1; i<20; i++) {
print(make(Array(i).fill(15n))) // longer and longer array...
}
NB: If you get an error running the above, try again with Chrome...
bit
is a bit of a misnomer here. Can you actually multiply the 4-bits directly by the exponent there? Typically the base conversion is done usingbit0 * 2**0
+bit1 * 2**1
+bit2 * 2**2
+bit3 * 2**3
, etc. I'm thinking I would have to break the 4-bit segments into individual bits and multiply each one by the increasing exponents.
– user633183
Mar 28 at 6:21
No point in guessing, I tried it an it works just fine. Thanks @trincot. I learned a useful shortcut in base conversion today!
– user633183
Mar 28 at 6:23
I never felt a "shortcoming" in JavaScript's bitwise operators before today. Is it even reasonable to expect a new set of bitwise operators that works in the 64-bit space?
– user633183
Mar 28 at 6:25
It is not really a shortcoming, but intended. I have added a new section to my answer which may interest you.
– trincot
Mar 28 at 8:00
that's great. I didn't know BigInt support was already here. The new section makes perfect sense.
– user633183
Mar 28 at 17:12
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55390991%2fhow-to-create-a-32-bit-integer-from-eight-8-4-bit-integers%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
The bitwise operators will result in a signed 32 bit number, meaning that if the bit at position 31 (counting from the least significant bit at the right, which is bit 0) is 1, the number will be negative.
To avoid this from happening, use other operators than <<
or |
, which both result in a signed 32-bit number. For instance:
(bit * 2**e) + make (more, e + 4)
Forcing unsigned 32-bit
Bit shifting operators are designed to force the result into the signed 32-bit range, at least that is claimed on mdn (at the time of writing):
The operands of all bitwise operators are converted to signed 32-bit integers
This is in fact not entirely true. The >>>
operator is an exception to this. EcmaScript 2015, section 12.5.8.1 states that the operands are mapped to unsigned 32 bit before shifting in the 0 bits. So even if you would shift zero bits, you'd see that effect.
You would only have to apply it once to the final value, like for instance in your print
function:
console.log((n>>>0).toString(2))
BigInt solution
If you need even more than 32 bits, and your JavaScript engine supports BigInt like some already do, then use BigInts for the operands involved in the bitwise operators -- these will then not use the 32-bit signed number wrapping (notice the n
suffixes):
const make = ([ bit, ...more ], e = 0n) =>
bit === undefined
? 0n
: (bit << e) + make (more, e + 4n)
const print = n =>
console.log(n.toString(2))
// Test
for (let i=1; i<20; i++) {
print(make(Array(i).fill(15n))) // longer and longer array...
}
NB: If you get an error running the above, try again with Chrome...
bit
is a bit of a misnomer here. Can you actually multiply the 4-bits directly by the exponent there? Typically the base conversion is done usingbit0 * 2**0
+bit1 * 2**1
+bit2 * 2**2
+bit3 * 2**3
, etc. I'm thinking I would have to break the 4-bit segments into individual bits and multiply each one by the increasing exponents.
– user633183
Mar 28 at 6:21
No point in guessing, I tried it an it works just fine. Thanks @trincot. I learned a useful shortcut in base conversion today!
– user633183
Mar 28 at 6:23
I never felt a "shortcoming" in JavaScript's bitwise operators before today. Is it even reasonable to expect a new set of bitwise operators that works in the 64-bit space?
– user633183
Mar 28 at 6:25
It is not really a shortcoming, but intended. I have added a new section to my answer which may interest you.
– trincot
Mar 28 at 8:00
that's great. I didn't know BigInt support was already here. The new section makes perfect sense.
– user633183
Mar 28 at 17:12
add a comment |
The bitwise operators will result in a signed 32 bit number, meaning that if the bit at position 31 (counting from the least significant bit at the right, which is bit 0) is 1, the number will be negative.
To avoid this from happening, use other operators than <<
or |
, which both result in a signed 32-bit number. For instance:
(bit * 2**e) + make (more, e + 4)
Forcing unsigned 32-bit
Bit shifting operators are designed to force the result into the signed 32-bit range, at least that is claimed on mdn (at the time of writing):
The operands of all bitwise operators are converted to signed 32-bit integers
This is in fact not entirely true. The >>>
operator is an exception to this. EcmaScript 2015, section 12.5.8.1 states that the operands are mapped to unsigned 32 bit before shifting in the 0 bits. So even if you would shift zero bits, you'd see that effect.
You would only have to apply it once to the final value, like for instance in your print
function:
console.log((n>>>0).toString(2))
BigInt solution
If you need even more than 32 bits, and your JavaScript engine supports BigInt like some already do, then use BigInts for the operands involved in the bitwise operators -- these will then not use the 32-bit signed number wrapping (notice the n
suffixes):
const make = ([ bit, ...more ], e = 0n) =>
bit === undefined
? 0n
: (bit << e) + make (more, e + 4n)
const print = n =>
console.log(n.toString(2))
// Test
for (let i=1; i<20; i++) {
print(make(Array(i).fill(15n))) // longer and longer array...
}
NB: If you get an error running the above, try again with Chrome...
bit
is a bit of a misnomer here. Can you actually multiply the 4-bits directly by the exponent there? Typically the base conversion is done usingbit0 * 2**0
+bit1 * 2**1
+bit2 * 2**2
+bit3 * 2**3
, etc. I'm thinking I would have to break the 4-bit segments into individual bits and multiply each one by the increasing exponents.
– user633183
Mar 28 at 6:21
No point in guessing, I tried it an it works just fine. Thanks @trincot. I learned a useful shortcut in base conversion today!
– user633183
Mar 28 at 6:23
I never felt a "shortcoming" in JavaScript's bitwise operators before today. Is it even reasonable to expect a new set of bitwise operators that works in the 64-bit space?
– user633183
Mar 28 at 6:25
It is not really a shortcoming, but intended. I have added a new section to my answer which may interest you.
– trincot
Mar 28 at 8:00
that's great. I didn't know BigInt support was already here. The new section makes perfect sense.
– user633183
Mar 28 at 17:12
add a comment |
The bitwise operators will result in a signed 32 bit number, meaning that if the bit at position 31 (counting from the least significant bit at the right, which is bit 0) is 1, the number will be negative.
To avoid this from happening, use other operators than <<
or |
, which both result in a signed 32-bit number. For instance:
(bit * 2**e) + make (more, e + 4)
Forcing unsigned 32-bit
Bit shifting operators are designed to force the result into the signed 32-bit range, at least that is claimed on mdn (at the time of writing):
The operands of all bitwise operators are converted to signed 32-bit integers
This is in fact not entirely true. The >>>
operator is an exception to this. EcmaScript 2015, section 12.5.8.1 states that the operands are mapped to unsigned 32 bit before shifting in the 0 bits. So even if you would shift zero bits, you'd see that effect.
You would only have to apply it once to the final value, like for instance in your print
function:
console.log((n>>>0).toString(2))
BigInt solution
If you need even more than 32 bits, and your JavaScript engine supports BigInt like some already do, then use BigInts for the operands involved in the bitwise operators -- these will then not use the 32-bit signed number wrapping (notice the n
suffixes):
const make = ([ bit, ...more ], e = 0n) =>
bit === undefined
? 0n
: (bit << e) + make (more, e + 4n)
const print = n =>
console.log(n.toString(2))
// Test
for (let i=1; i<20; i++) {
print(make(Array(i).fill(15n))) // longer and longer array...
}
NB: If you get an error running the above, try again with Chrome...
The bitwise operators will result in a signed 32 bit number, meaning that if the bit at position 31 (counting from the least significant bit at the right, which is bit 0) is 1, the number will be negative.
To avoid this from happening, use other operators than <<
or |
, which both result in a signed 32-bit number. For instance:
(bit * 2**e) + make (more, e + 4)
Forcing unsigned 32-bit
Bit shifting operators are designed to force the result into the signed 32-bit range, at least that is claimed on mdn (at the time of writing):
The operands of all bitwise operators are converted to signed 32-bit integers
This is in fact not entirely true. The >>>
operator is an exception to this. EcmaScript 2015, section 12.5.8.1 states that the operands are mapped to unsigned 32 bit before shifting in the 0 bits. So even if you would shift zero bits, you'd see that effect.
You would only have to apply it once to the final value, like for instance in your print
function:
console.log((n>>>0).toString(2))
BigInt solution
If you need even more than 32 bits, and your JavaScript engine supports BigInt like some already do, then use BigInts for the operands involved in the bitwise operators -- these will then not use the 32-bit signed number wrapping (notice the n
suffixes):
const make = ([ bit, ...more ], e = 0n) =>
bit === undefined
? 0n
: (bit << e) + make (more, e + 4n)
const print = n =>
console.log(n.toString(2))
// Test
for (let i=1; i<20; i++) {
print(make(Array(i).fill(15n))) // longer and longer array...
}
NB: If you get an error running the above, try again with Chrome...
const make = ([ bit, ...more ], e = 0n) =>
bit === undefined
? 0n
: (bit << e) + make (more, e + 4n)
const print = n =>
console.log(n.toString(2))
// Test
for (let i=1; i<20; i++) {
print(make(Array(i).fill(15n))) // longer and longer array...
}
const make = ([ bit, ...more ], e = 0n) =>
bit === undefined
? 0n
: (bit << e) + make (more, e + 4n)
const print = n =>
console.log(n.toString(2))
// Test
for (let i=1; i<20; i++) {
print(make(Array(i).fill(15n))) // longer and longer array...
}
edited Mar 28 at 18:36
answered Mar 28 at 6:18
trincottrincot
130k1691125
130k1691125
bit
is a bit of a misnomer here. Can you actually multiply the 4-bits directly by the exponent there? Typically the base conversion is done usingbit0 * 2**0
+bit1 * 2**1
+bit2 * 2**2
+bit3 * 2**3
, etc. I'm thinking I would have to break the 4-bit segments into individual bits and multiply each one by the increasing exponents.
– user633183
Mar 28 at 6:21
No point in guessing, I tried it an it works just fine. Thanks @trincot. I learned a useful shortcut in base conversion today!
– user633183
Mar 28 at 6:23
I never felt a "shortcoming" in JavaScript's bitwise operators before today. Is it even reasonable to expect a new set of bitwise operators that works in the 64-bit space?
– user633183
Mar 28 at 6:25
It is not really a shortcoming, but intended. I have added a new section to my answer which may interest you.
– trincot
Mar 28 at 8:00
that's great. I didn't know BigInt support was already here. The new section makes perfect sense.
– user633183
Mar 28 at 17:12
add a comment |
bit
is a bit of a misnomer here. Can you actually multiply the 4-bits directly by the exponent there? Typically the base conversion is done usingbit0 * 2**0
+bit1 * 2**1
+bit2 * 2**2
+bit3 * 2**3
, etc. I'm thinking I would have to break the 4-bit segments into individual bits and multiply each one by the increasing exponents.
– user633183
Mar 28 at 6:21
No point in guessing, I tried it an it works just fine. Thanks @trincot. I learned a useful shortcut in base conversion today!
– user633183
Mar 28 at 6:23
I never felt a "shortcoming" in JavaScript's bitwise operators before today. Is it even reasonable to expect a new set of bitwise operators that works in the 64-bit space?
– user633183
Mar 28 at 6:25
It is not really a shortcoming, but intended. I have added a new section to my answer which may interest you.
– trincot
Mar 28 at 8:00
that's great. I didn't know BigInt support was already here. The new section makes perfect sense.
– user633183
Mar 28 at 17:12
bit
is a bit of a misnomer here. Can you actually multiply the 4-bits directly by the exponent there? Typically the base conversion is done using bit0 * 2**0
+ bit1 * 2**1
+ bit2 * 2**2
+ bit3 * 2**3
, etc. I'm thinking I would have to break the 4-bit segments into individual bits and multiply each one by the increasing exponents.– user633183
Mar 28 at 6:21
bit
is a bit of a misnomer here. Can you actually multiply the 4-bits directly by the exponent there? Typically the base conversion is done using bit0 * 2**0
+ bit1 * 2**1
+ bit2 * 2**2
+ bit3 * 2**3
, etc. I'm thinking I would have to break the 4-bit segments into individual bits and multiply each one by the increasing exponents.– user633183
Mar 28 at 6:21
No point in guessing, I tried it an it works just fine. Thanks @trincot. I learned a useful shortcut in base conversion today!
– user633183
Mar 28 at 6:23
No point in guessing, I tried it an it works just fine. Thanks @trincot. I learned a useful shortcut in base conversion today!
– user633183
Mar 28 at 6:23
I never felt a "shortcoming" in JavaScript's bitwise operators before today. Is it even reasonable to expect a new set of bitwise operators that works in the 64-bit space?
– user633183
Mar 28 at 6:25
I never felt a "shortcoming" in JavaScript's bitwise operators before today. Is it even reasonable to expect a new set of bitwise operators that works in the 64-bit space?
– user633183
Mar 28 at 6:25
It is not really a shortcoming, but intended. I have added a new section to my answer which may interest you.
– trincot
Mar 28 at 8:00
It is not really a shortcoming, but intended. I have added a new section to my answer which may interest you.
– trincot
Mar 28 at 8:00
that's great. I didn't know BigInt support was already here. The new section makes perfect sense.
– user633183
Mar 28 at 17:12
that's great. I didn't know BigInt support was already here. The new section makes perfect sense.
– user633183
Mar 28 at 17:12
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55390991%2fhow-to-create-a-32-bit-integer-from-eight-8-4-bit-integers%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
It looks like bitwise operators says "The numbers
-2147483648
and2147483647
are the minimum and the maximum integers representable through a 32-bit signed number." Indeed(15 << 28)
lies beyond this range, however JavaScript's MAX_SAFE_INTEGER supports up to 53 bits. Is there a safe and reliable way to use bitwise operators on larger-than-32-bit numbers?– user633183
Mar 28 at 6:10
Is the signedness really unacceptable? They're the same bits after all, just slightly a different interpretation
– harold
Mar 28 at 11:00