bit-manipulation
v1.0.0
Published
An ES module providing functions for setting and clearing bits (and doing any bitwise operations) in Numbers up to 53 bits and in BigInts of any bit-width. In addition there's also functions to manipulate the bits in JavaScript's 64-bit floats and represe
Downloads
6
Maintainers
Readme
bit-manipulation
Description
An ES module providing functions for setting and clearing bits (and doing any bitwise operations) in Numbers up to 53 bits and in BigInts of any bit-width. In addition there's also functions to manipulate the bits in JavaScript's 64-bit floats and representing integers (in two's complement format) in binary or hex. It also has functions to check if any bits are set or not.
If you're new to JavaScript it might sound strange to have a library for doing bitwise operations since JavaScript has operators for this inbuilt in the language. But the problem is that the inbuilt operators converts any operands into 32-bit signed integers, hence they can't return a result that is over 32 bits AND they treat bit 32 as the sign bit (although >>> 0
can be used to get an unsigned result).
Funding
If you find this useful then please consider helping me out (I'm jobless and sick). For more information visit my GitHub profile.
How to use
Install using NPM
npm i bit-manipulation
Import the ES module into Node.js
import * as bm from 'bit-manipulation'
Got problems using ES modules? This might help or read the documentation.
Import the ES module into the browser or Deno
import * as bm from '/node_modules/bit-manipulation/source/bitManipulation.js'
Example
import * as bm from 'bit-manipulation'
const log = console.log // yes, this is handy
// Classical use of (some of) the functions in this library
let v = 0b1000_0000
v = bm.set(v, 1,2,3,4) // set these bits in v and return the result
log(bm.numberToBinary(v))
v = bm.xor(v, 0xFF) // xor v with 0xFF
log(bm.numberToBinary(v))
log(bm.isSet(v, 1)) // check if the LSB is set
log(v) // the value in base 10
log() // Wrapping a value in bm.Serial allows us to do the same operations on it in series in a more convenient way
v = bm.serial(0b1000_0000)
.set(1,2,3,4).log('bin')
.xor(0xFF).log('bin')
log(v.isSet(1))
log(v.out()) // then .out() returns the result
log() // You can go mad with that
bm.serial(0).set(1,8).xor(0xFF).and(0b1111).or(0xF0).flip(1,8).not(8).log('bin')
log() // And then debug your madness for better clarity
bm.serial(0).set(1,8).log(2).xor(0xFF).log(2).and(0b1111).log(2).or(0xF0).log(2).flip(1,8).log(2).not(8).log(2)
log() // There's lots of fun to be had
log(bm.numberToHex(bm.reverseBitOrder(0xD00D, 16), 2))
log() // And yes, you can set bits higher than bit 32
log(bm.numberToBinary(bm.set(0, 33, 53), 64))
log(bm.numberToBinary(bm.set(0n, 33, 64))) // even higher than bit 53 if using BigInts
// And bitwise operations works fine on them
log(bm.numberToBinary(bm.or(bm.set(0, 33, 53), 1), 64))
log(bm.numberToBinary(bm.or(bm.set(0n, 33, 64), 1)))
log() // Did you ever want to mess around with the bits in a 64-bit float? Well, now you can!
let bits = bm.float.toBits(1.23456) // returns an overview of any set bits
log(bits)
log(bm.float.fromBits(bits)) // and can be used to create a float
let float = bm.float.set(1.23456, {signBit: true}) // set the sign bit
log(float)
float = bm.float.clear(float, {signBit: true}) // clear it
log(bm.float.set(float, {significand: [51]})) // and set bit 51 in the significand / mantissa
// you can even set bits using values
float = bm.float.fromBits({exponent: 0b1100_0001, significand: 0xF_FFFF_FFFF_FFFF})
log(bm.float.toBits(float)) // check that it worked correctly
log(float) // also let's check what that float looks like
log() // There's also an educational value in learning about two's complement format
log(bm.negativeIntegerFromBits(1)) // the bits to set to 0
log(bm.negativeIntegerFromValue(0b10)) // same as this (where the MSB is the sign bit)
log() // And I'm sure that you at least once wanted to know the bit length/width of a number
log(bm.bitLength(0xFFFF_FFFF))
log(bm.bitLength(0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFFn))
log('Please tell your mom and dad about this! 🙂')
Console output from example (for those without a computer):
0b10001111
0b01110000
false
112
0b10001111
0b01110000
false
112
0b10000000
0b10000001
0b01111110
0b00001110
0b11111110
0b01111111
0b10000000
0xB00B
0b00000000_00010000_00000000_00000001_00000000_00000000_00000000_00000000
0b10000000_00000000_00000000_00000001_00000000_00000000_00000000_00000000n
0b00000000_00010000_00000000_00000001_00000000_00000000_00000000_00000001
0b10000000_00000000_00000000_00000001_00000000_00000000_00000000_00000001n
{
signBit: false,
exponent: [
1, 2, 3, 4, 5,
6, 7, 8, 9, 10
],
significand: [
4, 5, 6, 10, 13, 14, 17, 18,
19, 20, 24, 27, 28, 29, 30, 31,
32, 33, 39, 40, 47, 48, 49, 50
]
}
1.23456
-1.23456
1.48456
{
signBit: false,
exponent: [ 1, 7, 8 ],
significand: [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
45, 46, 47, 48, 49, 50, 51, 52
]
}
2.793402995719818e-250
-2
-2
32
96
Auto-generated API documentation (from JSDoc)
Modules
Objects
bit-manipulation
- bit-manipulation
- .Serial
- new exports.Serial(value)
- .x(func)
- .out([base]) ⇒ number | bigint | string
- .log([base])
- .not(bitLength)
- .reverseBitOrder(bitLength)
- .rShift(offset)
- .lShift(offset)
- .and()
- .or()
- .xor()
- .set(...bits)
- .clear(...bits)
- .flip(...bits)
- .isSet(...bits) ⇒ boolean
- .isAnySet(...bits) ⇒ boolean
- .isNotSet(...bits) ⇒ boolean
- .bitLength() ⇒ number
- .set(value, ...bits) ⇒ number | bigint
- .clear(value, ...bits) ⇒ number | bigint
- .flip(value, ...bits) ⇒ number | bigint
- .isAnySet(value, ...bits) ⇒ boolean
- .isSet(value, ...bits) ⇒ boolean
- .isNotSet(value, ...bits) ⇒ boolean
- .lShift(value, offset) ⇒ number | bigint
- .rShift(value, offset) ⇒ number | bigint
- .xor(value1, value2) ⇒ number | bigint
- .or(value1, value2) ⇒ number | bigint
- .and(value1, value2) ⇒ number | bigint
- .not(value, [bitLength]) ⇒ number | bigint
- .reverseBitOrder(value, bitLength) ⇒ number | bigint
- .bitLength(value) ⇒ number
- .bitmask(...bits) ⇒ number | bigint
- .bitmask_allSet(numBits) ⇒ number | bigint
- .integerFromBits(...bits) ⇒ number | bigint
- .negativeIntegerFromBits(...bits) ⇒ number | bigint
- .negativeIntegerFromValue(value) ⇒ number | bigint
- .serial(value) ⇒ Serial
- .numberToHex(number, [paddingByteSize], [grouping], [showPrefix]) ⇒ string
- .numberToBinary(number, [paddingBits], [grouping], [showPrefix]) ⇒ string
- .Serial
bm.Serial
A class allowing multiple bitwise operations done in serial order on a value (for convenience). Call out()
to return the result when done. This class actually has most of the functions in this library as its methods.
Kind: static class of bit-manipulation
- .Serial
- new exports.Serial(value)
- .x(func)
- .out([base]) ⇒ number | bigint | string
- .log([base])
- .not(bitLength)
- .reverseBitOrder(bitLength)
- .rShift(offset)
- .lShift(offset)
- .and()
- .or()
- .xor()
- .set(...bits)
- .clear(...bits)
- .flip(...bits)
- .isSet(...bits) ⇒ boolean
- .isAnySet(...bits) ⇒ boolean
- .isNotSet(...bits) ⇒ boolean
- .bitLength() ⇒ number
new exports.Serial(value)
| Param | Type | Description | | --- | --- | --- | | value | number | bigint | Enter the value to operate on, must be an integer. |
serial.x(func)
Manipulate or read the value using your own function, return nothing if no change is to be made or return the new value.
Kind: instance method of Serial
| Param | Type | Description | | --- | --- | --- | | func | function | A function which will receive the value. |
serial.out([base]) ⇒ number | bigint | string
Returns the value operated on.
Kind: instance method of Serial
| Param | Type | Description | | --- | --- | --- | | [base] | number | string | The base to use. Defaults to base 10, also supports base 2 and 16. |
serial.log([base])
A shortcut to logging the value using console.log
. But with options for using a binary or hexadecimal representation.
Kind: instance method of Serial
| Param | Type | Description | | --- | --- | --- | | [base] | number | string | The base to use. Defaults to base 10, also supports base 2 and 16. |
serial.not(bitLength)
Bitwise NOT (invert the bits). If not specifying a bitLength
to operate within then inverting the bits using not
will turn any positive number into a negative one because the sign bit (which is virtual when using this library by the way) will be inverted as well.
Kind: instance method of Serial
| Param | Type | | --- | --- | | bitLength | number |
serial.reverseBitOrder(bitLength)
Reverse the bit order up to the bitLength
supplied, the result will be capped to this size.
Kind: instance method of Serial
| Param | Type | Description | | --- | --- | --- | | bitLength | number | The wanted bit length of the result (the position of the most significant bit). |
serial.rShift(offset)
Shift the bits towards the right (the least significant side) offset
amount of bits. Bits shifted in from the left will be set to 0.
Kind: instance method of Serial
| Param | Type | Description | | --- | --- | --- | | offset | number | How far to shift the bits. |
serial.lShift(offset)
Shift the bits towards the left (the most significant side) offset
amount of bits. Bits shifted in from the right will be set to 0.
Kind: instance method of Serial
| Param | Type | Description | | --- | --- | --- | | offset | number | How far to shift the bits. |
serial.and()
Bitwise AND
Kind: instance method of Serial
serial.or()
Bitwise OR
Kind: instance method of Serial
serial.xor()
Bitwise XOR
Kind: instance method of Serial
serial.set(...bits)
Set (as in setting them to 1) these bits (others retain their state).
Kind: instance method of Serial
| Param | Type | Description | | --- | --- | --- | | ...bits | number | Which bits to set, where 1 means the least significant bit. |
serial.clear(...bits)
Clear (as in setting them to 0) these bits (others retain their state).
Kind: instance method of Serial
| Param | Type | Description | | --- | --- | --- | | ...bits | number | Which bits to clear, where 1 means the least significant bit. |
serial.flip(...bits)
Flip (or toggle) these bits (others retain their state).
Kind: instance method of Serial
| Param | Type | Description | | --- | --- | --- | | ...bits | number | Which bits to flip, where 1 means the least significant bit. |
serial.isSet(...bits) ⇒ boolean
Check if all of these bits are set (as in having a state of 1).
Kind: instance method of Serial
Returns: boolean - True or false
| Param | Type | Description | | --- | --- | --- | | ...bits | number | Which bits to check. |
serial.isAnySet(...bits) ⇒ boolean
Check if any of these bits are set (as in having a state of 1).
Kind: instance method of Serial
Returns: boolean - True or false
| Param | Type | Description | | --- | --- | --- | | ...bits | number | Which bits to check. |
serial.isNotSet(...bits) ⇒ boolean
Check if all of these bits are not set (as in having a state of 0).
Kind: instance method of Serial
Returns: boolean - True or false
| Param | Type | Description | | --- | --- | --- | | ...bits | number | Which bits to check. |
serial.bitLength() ⇒ number
Returns the number of bits needed to be able to represent the value. For negative numbers this does not include the sign bit.
Kind: instance method of Serial
Returns: number - The bit length of the value.
bm.set(value, ...bits) ⇒ number | bigint
Set (as in setting them to 1) these bits in the value (others retain their state).
Kind: static method of bit-manipulation
| Param | Type | Description | | --- | --- | --- | | value | number | bigint | The value to operate on. | | ...bits | number | Which bits to set, where 1 means the least significant bit. |
bm.clear(value, ...bits) ⇒ number | bigint
Clear (as in setting them to 0) these bits in the value (others retain their state).
Kind: static method of bit-manipulation
| Param | Type | Description | | --- | --- | --- | | value | number | bigint | The value to operate on. | | ...bits | number | Which bits to clear, where 1 means the least significant bit. |
bm.flip(value, ...bits) ⇒ number | bigint
Flip (or toggle) these bits in the value (others retain their state).
Kind: static method of bit-manipulation
| Param | Type | Description | | --- | --- | --- | | value | number | bigint | The value to operate on. | | ...bits | number | Which bits to flip, where 1 means the least significant bit. |
bm.isAnySet(value, ...bits) ⇒ boolean
Check if any of these bits are set (as in having a state of 1) in the value.
Kind: static method of bit-manipulation
Returns: boolean - True or false
| Param | Type | Description | | --- | --- | --- | | value | number | bigint | The value to check. | | ...bits | number | Which bits to check. |
bm.isSet(value, ...bits) ⇒ boolean
Check if all of these bits are set (as in having a state of 1) in the value.
Kind: static method of bit-manipulation
Returns: boolean - True or false
| Param | Type | Description | | --- | --- | --- | | value | number | bigint | The value to check. | | ...bits | number | Which bits to check. |
bm.isNotSet(value, ...bits) ⇒ boolean
Check if all of these bits are not set (as in having a state of 0) in the value.
Kind: static method of bit-manipulation
Returns: boolean - True or false
| Param | Type | Description | | --- | --- | --- | | value | number | bigint | The value to check. | | ...bits | number | Which bits to check. |
bm.lShift(value, offset) ⇒ number | bigint
Shift the bits in the value towards the left (the most significant side) offset
amount of bits. Bits shifted in from the right will be set to 0.
Kind: static method of bit-manipulation
Returns: number | bigint - The result.
| Param | Type | Description | | --- | --- | --- | | value | number | bigint | The value to operate on. | | offset | number | How far to shift the bits. |
bm.rShift(value, offset) ⇒ number | bigint
Shift the bits in the value towards the right (the least significant side) offset
amount of bits. Bits shifted in from the left will be set to 0.
Kind: static method of bit-manipulation
Returns: number | bigint - The result.
| Param | Type | Description | | --- | --- | --- | | value | number | bigint | The value to operate on. | | offset | number | How far to shift the bits. |
bm.xor(value1, value2) ⇒ number | bigint
Bitwise XOR (exclusive or) value1
with value2
and return the result.
Kind: static method of bit-manipulation
| Param | Type | | --- | --- | | value1 | number | bigint | | value2 | number | bigint |
bm.or(value1, value2) ⇒ number | bigint
Bitwise OR value1
with value2
and return the result.
Kind: static method of bit-manipulation
| Param | Type | | --- | --- | | value1 | number | bigint | | value2 | number | bigint |
bm.and(value1, value2) ⇒ number | bigint
Bitwise AND value1
with value2
and return the result.
Kind: static method of bit-manipulation
| Param | Type | | --- | --- | | value1 | number | bigint | | value2 | number | bigint |
bm.not(value, [bitLength]) ⇒ number | bigint
Bitwise NOT value
(invert the bits) and return the result. If not specifying a bitLength to operate within then inverting the bits using not
will turn any positive number into a negative one because the sign bit (which is virtual when using this library by the way) will be inverted as well.
Kind: static method of bit-manipulation
Returns: number | bigint - The result.
| Param | Type | Description |
| --- | --- | --- |
| value | number | bigint | The value to operate on. |
| [bitLength] | number | The bit length to operate within, set it to restrict the NOT operation to only the first bitLength
bits of the value. Then you can not in any way invert the sign bit. |
bm.reverseBitOrder(value, bitLength) ⇒ number | bigint
Reverse the bit order of the value up to the bitLength
supplied, the returned value will be capped to this size.
Kind: static method of bit-manipulation
Returns: number | bigint - The result.
| Param | Type | Description | | --- | --- | --- | | value | number | bigint | The value to operate on. | | bitLength | number | The wanted bit length of the returned value (the position of the most significant bit). |
bm.bitLength(value) ⇒ number
Returns the number of bits needed to be able to represent the value. For negative numbers this does not include the sign bit.
Kind: static method of bit-manipulation
Returns: number - The bit length of the value.
| Param | Type | Description | | --- | --- | --- | | value | number | bigint | The value to measure the length in bits of. |
bm.bitmask(...bits) ⇒ number | bigint
Create a bitmask (which is a value with bits in these positions set). If setting bits over bit 32 then it returns a BigInt.
Kind: static method of bit-manipulation
| Param | Type | Description | | --- | --- | --- | | ...bits | number | The bit positions of any set (as in 1) bits. |
bm.bitmask_allSet(numBits) ⇒ number | bigint
Create a bitmask with a length of numBits
where all the bits are set, if numBits
is more than 53 then a BigInt
will be returned.
Kind: static method of bit-manipulation
Returns: number | bigint - The bitmask.
| Param | Type | Description | | --- | --- | --- | | numBits | number | Defines how wide (in bits) the bitmask is. |
Example
bitmask_allSet(32) == 0xFFFF_FFFF
bm.integerFromBits(...bits) ⇒ number | bigint
Create a positive integer with only these bits set. If setting bits over bit 53 (> Number.MAX_SAFE_INTEGER
) then a BigInt is returned.
Kind: static method of bit-manipulation
| Param | Type | Description | | --- | --- | --- | | ...bits | number | Which bits to set, where 1 means the least significant bit. |
bm.negativeIntegerFromBits(...bits) ⇒ number | bigint
Create a negative integer (two's complement) from which bit positions should be set to 0.
Kind: static method of bit-manipulation
| Param | Type | Description | | --- | --- | --- | | ...bits | number | Which bits to set to 0, where 1 means the least significant bit. |
bm.negativeIntegerFromValue(value) ⇒ number | bigint
Create a negative integer (two's complement) from the bits in a value. One use case could be that you read the bits into an unsigned integer, but you actually wanted those bits to be represented as a negative number. Or educational use.
Kind: static method of bit-manipulation
| Param | Type | Description | | --- | --- | --- | | value | number | bigint | The value with bits representing a negative number in two's complement format. |
bm.serial(value) ⇒ Serial
If you want to do multiple bitwise operations (in serial order) then this will wrap the value in a class which has most of the functions in this library as its methods. Call out()
to return the result when done.
Kind: static method of bit-manipulation
| Param | Type | | --- | --- | | value | number | bigint |
Example
serial(value).rShift(32).and(0xFFFF_FFFF).out()
bm.numberToHex(number, [paddingByteSize], [grouping], [showPrefix]) ⇒ string
Converts any Number
or BigInt
into a hexadecimal representation.
Numbers with a fractional part will represented in the IEEE 754 double-precision binary format. Where the first bit is the sign bit, followed by the exponent (11 bits) and the significand / mantissa (52 bits).
Other numbers (integers) will be represented in the two's complement format. Where negative numbers are actually displayed correctly compared to when using (number).toString(16)
.
Kind: static method of bit-manipulation
Returns: string - The hexadecimal representation.
| Param | Type | Default | Description | | --- | --- | --- | --- | | number | number | | The number to convert to hex. | | [paddingByteSize] | number | 4 | How many bytes to align the output with. | | [grouping] | number | 4 | Group the output into chunks of this size. | | [showPrefix] | boolean | true | Whether to prefix the output with 0x or not. |
bm.numberToBinary(number, [paddingBits], [grouping], [showPrefix]) ⇒ string
Converts any Number
or BigInt
into a binary representation.
Numbers with a fractional part will represented in the IEEE 754 double-precision binary format. Where the first bit is the sign bit, followed by the exponent (11 bits) and the significand / mantissa (52 bits).
Other numbers (integers) will be represented in the two's complement format. Where negative numbers are actually displayed correctly compared to when using (number).toString(2)
.
Kind: static method of bit-manipulation
Returns: string - The binary representation.
| Param | Type | Default | Description | | --- | --- | --- | --- | | number | number | | The number to convert to binary. | | [paddingBits] | number | 8 | How many bits to align the output with. | | [grouping] | number | 4 | Group the output into chunks of this size. | | [showPrefix] | boolean | true | Whether to prefix the output with 0b or not. |
float : object
I failed finding any way for jsdoc-to-markdown to document the float
namespace as being part of the bit-manipulation
module, but it is...
Kind: global namespace
float.fromBits ⇒ number
Create a (64-bit double precision) floating point number by setting the bits in its exponent
and significand
(often called the mantissa). Set the signBit
to turn the float into a negative number. For help see this: https://en.wikipedia.org/wiki/Double-precision_floating-point_format
Kind: static property of float
Returns: number - A 64-bit float.
| Param | Type | Description | | --- | --- | --- | | parts | object | The object holding information about which bits in the float is set. | | parts.exponent | number | Array.<number> | The exponent. | | parts.significand | number | bigint | Array.<number> | The fractional part. | | parts.signBit | boolean | Set it to make the float negative. |
float.toBits ⇒ object
Convert a (64-bit double precision) floating point number into an object with information about which bits are set. The exponent and significand (often called the mantissa) are returned as arrays containing the bit positions of any set bits (as in bits that are 1).
Kind: static property of float
Returns: object - {signBit, exponent, significand}
| Param | Type | | --- | --- | | float | number |
float.set ⇒ number
Set bits (as in setting them to 1) in the float supplied. This is done using an object with information about which bits to set in the exponent
and the significand
. Set the signBit
to turn the float into a negative number.
Kind: static property of float
Returns: number - A 64-bit float.
| Param | Type | Description | | --- | --- | --- | | float | number | The float to manipulate. | | parts | object | The object holding information about which bits to set. | | parts.exponent | number | Array.<number> | The exponent. | | parts.significand | number | bigint | Array.<number> | The fractional part. | | parts.signBit | boolean | Set it to make the float negative. |
float.clear ⇒ number
Clear bits (as in setting them to 0) in the float supplied. This is done using an object with information about which bits to clear in the exponent and the significand.
Kind: static property of float
Returns: number - A 64-bit float.
| Param | Type | Description | | --- | --- | --- | | float | number | The float to manipulate. | | parts | object | The object holding information about which bits to clear. | | parts.exponent | number | Array.<number> | The exponent. | | parts.significand | number | bigint | Array.<number> | The fractional part. | | parts.signBit | boolean | Clear it to make a negative float positive. |
End of readme
Death is not the end of your consciousness, it's the expansion of it.