How to get Number of bits from Hex - javascript

For example how do I get 8 from 0x01, or 16 from 0x0001.
I want to know the number of bits a variable has.
var someNumber = 0x123456;
var len = whatToDoHere(someNumber);
console.log(len); // => 24 for example

Here are few alternatives:
f1 = n => (Math.log2(n) & -8) + 8 // log2 (-Infinity & -8 = 0)
f2 = n => ((n >>= 8) && f2(n)) + 8 // recursion
f3 = n => n.toString(16).length + 1 << 2 & -8 // string length
for (n of [0, 0xff, 0x100, 0xffff, 0x10000, 0xffffff])
console.log( f1(n) + '\t' + f2(n) + '\t' + f3(n) + '\t0x' + n.toString(16) )

A number is just a number, it does not have any particular representation attached to it. Even if you say that it would be formatted in base16 (as hex) or base256 (bytes), that doesn't say anything about the number of leading zeroes (as in 0x01 vs 0x0001). If you know that however, you'd already know how many digits your formatted number has.

Another possible solution is to convert to a hex string and then measure the length of the string:
const someNumber = 0x123456;
const hexString = someNumber.toString( 16 );
const numberOfBits = hexString.length * 4; //each character is half a byte
console.log( "Number of bits: ", numberOfBits );

Related

Change number to corresponding letters

My question is how do I get the corresponding letter(s) from a number.
So
0 => 0 // 0 stays 0
1 => A
2 => B
3 => C
26 => Z
27 => AA
28 => AB
55 => AC
702 => ZZ
The number will definitely not be over 702.
Is there some kind of method I can use to do this?
Split the number into parts by doing a modulo by 26, then use String.fromCharCode to convert it to a character:
function numToExcelColumnName(n){
if(!n) return 0
n-- //Make 0 => A
const lower = n % 26
const upper = Math.floor(n / 26)
return (
upper
? String.fromCharCode(65 + upper - 1)
: ''
)
+ String.fromCharCode(65 + lower)
}
You can even extend this code to handle numbers above 702 as well by adding a loop:
function numToExcelColumnName(n){
if(!n) return 0
let output = ''
while(n){
n--
output = String.fromCharCode(65 + n % 26) + output
n = Math.floor(n / 26)
}
return output
}
For single characters like A,B... you can get the number easily by
num = ord(x)-65 where x is the corresponding character (A,B...)
For Double letters like (AB,BG,..)
num = ord(str[0]-65)*26+(str[1]-65) where str = xy where x and y are corresponding characters
I liked the challenge, so I wrote the following code:
function NumbersToLetters(num) {
var letArr=[];
function numToLet(letterArray, number) {
if(number>0) {
var whole=Math.floor((number-1)/26);
var reminder=(number-1)%26;
letterArray.unshift(String.fromCharCode(65+reminder));
numToLet(letterArray, whole);
}
};
numToLetters(letArr, num);
return letArr.length?letArr.join(""):"0";
}
To be used:
NumbersToLetters(num);

Get the exact decimal representation of a JavaScript number

Every finite number in JavaScript has an exact real value. For example:
const x = Number.MAX_VALUE
Here, x has the precise value of 21024 - 2971 =
179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368
and we can demonstrate this by using x in arithmetic:
console.log(x % 10000) // 8368
But how can I get all of those decimal digits?
I'd like it if the solution also worked for non-integers, for example const y = Number.EPSILON is precisely 2-52 =
0.0000000000000002220446049250313080847263336181640625
The most effective way I've found to do this is to
write the float into an ArrayBuffer, then read it back as a 64-bit unsigned BigInt
extract the sign, exponent and mantissa using bitwise operations
compute the desired result multiplied by a large power of 10
use string operations on the stringified BigInt to insert a decimal point in the right place.
For example:
const SIGN_BITS = 1n
const EXPONENT_BITS = 11n
const MANTISSA_BITS = 52n
const BIAS = 1023n
export const stringify = value => {
if (typeof value !== 'number') {
throw Error('Not a number')
}
if (!Number.isFinite(value)) {
return String(value)
}
const dataView = new DataView(new ArrayBuffer(8))
dataView.setFloat64(0, value)
const bigUint64 = dataView.getBigUint64(0)
const mantissaBits = (bigUint64 >> 0n) & ((1n << MANTISSA_BITS) - 1n)
const exponentBits = (bigUint64 >> MANTISSA_BITS) & ((1n << EXPONENT_BITS) - 1n)
const signBits = (bigUint64 >> (MANTISSA_BITS + EXPONENT_BITS)) & ((1n << SIGN_BITS) - 1n)
const sign = signBits === 0b0n ? '' : '-'
const isSubnormal = exponentBits === 0b0n
// So as to keep this in integers, multiply the fraction by 2 ** 52 while subtracting
// that same power from the exponent
const m = ((isSubnormal ? 0n : 1n) << MANTISSA_BITS) + mantissaBits
const e = (isSubnormal ? 1n : exponentBits) - BIAS - MANTISSA_BITS
if (e >= 0n) {
// Pure integers, no problem
return sign + String(m << e)
}
// Multiply by a large enough power of 10 that all possible decimal digits are preserved
// when we then divide by the power of 2
const power10 = 10n ** -e
const f = (m * power10) >> -e
const pre = f / power10
const post = f % power10
if (post === 0n) {
return sign + String(pre)
}
return sign + String(pre) + '.' + String(post).padStart(Number(-e), '0').replace(/0+$/, '')
}
console.log(stringify(Number.MAX_VALUE))
This outputs:
179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368
Similarly:
console.log(stringify(Number.EPSILON))
outputs:
0.0000000000000002220446049250313080847263336181640625
You mis understand floating point.
You get a max of about 14 digits as there is no more precision than. 2^52
The max number is a number that has three parts.
The sign, positive or negative and is 1 bit. Thus you get 0 and -0
The Fraction 52 bits that gives the precision of about 14 digits.
The exponent 11 bits and is a signed value that is the amount to multiply the Fraction value with. 2 ^ exponent
See wiki Double-precision_floating-point_format for more info.

Most efficient method to check for range of numbers within number without duplicates

Given a number n , a minimum number min , a maximum number max , what is the most efficient method to determine
Number n is or is not within range , inclusive of , min - max
Number n does or does not contain duplicate numbers
Efficiency meaning here that the method or set of methods requires the least amount of computational resources and returns either true or false in the least amount of time
Context: Condition at if within a for loop which could require from thousands to hundreds of thousands of iterations to return a result; where milliseconds required to return true or false as to Number check could affect performance
At Profiles panel at DevTools on a collection of 71,3307 items iterated, RegExp below was listed as using 27.2ms of total 1097.3ms to complete loop . At a collection of 836,7628 items iterated RegExp below used 193.5ms within total of 11285.3ms .
Requirement: Most efficient method to return Boolean true or false given above parameters , within the least amount of time.
Note: Solution does not have to be limited to RegExp ; used below as the pattern returned expected results.
Current js utilizing RegExp re , RegExp.protype.test()
var min = 2
, max = 7
, re = new RegExp("[" + min + "-" + max + "](.)(?!=\1)", "g")
, arr = [81, 35, 22, 45, 49];
for (var i = 0; i < arr.length; i++) {
console.log(re.test(arr[i]), i, arr[i])
/*
false 0 81
true 1 35
false 2 22
true 3 45
false 4 49
*/
}
Associative arrays approach:
This has the advantage of being easily understandable.
function checkDigits(min, max, n) {
var digits = Array(10); // Declare the length of the array (the 10 digits) to avoid any further memory allocation
while (n) {
d = (n % 10); // Get last digit
n = n / 10 >>0; // Remove it from our number (the >>0 bit is equivalent to compose(Math.floor, Math.abs))
if (d < min || d > max || digits[d]) // Test if "d" is outside the range or if it has been checked in the "digits" array
return false;
else
digits[d] = true; // Mark the digit as existing
}
}
var min = 2
, max = 7
, arr = [81, 35, 22, 45, 49];
function checkDigits(min, max, n) {
var digits = Array(10); // Declare the length of the array (the 10 digits) to avoid any further memory allocation
while (n) {
d = (n % 10); // Get last digit
n = n / 10 >>0; // Remove it from our number (the >>0 bit is equivalent to compose(Math.floor, Math.abs))
if (d < min || d > max || digits[d]) // Test if "d" is outside the range or if it has been checked in the "digits" array
return false;
else
digits[d] = true; // Mark the digit as existing
}
return true;
}
for (var i = 0; i < arr.length; i++) {
console.log(checkDigits(min, max, arr[i]), i, arr[i])
}
Binary mask approach:
This replaces the Array with an integer that is in effect used as an array of bits. It should be faster.
function checkDigits(min, max, n) {
var digits = 0;
while (n) {
d = (n % 10);
n = n / 10 >>0;
if (d < min || d > max || (digits & (1 << d)))
return false;
else
digits |= 1 << d;
}
return true;
}
function checkDigits(min, max, n) {
var digits = 0;
while (n) {
d = (n % 10);
n = n / 10 >>0;
if (d < min || d > max || (digits & (1 << d)))
return false;
else
digits |= 1 << d;
}
return true;
}
Explanation for binary mask approach:
1 << d creates a bit mask, an integer with the d bit set and all other bits set to 0.
digits |= 1 << d sets the bit marked by our bit mask on the integer digits.
digits & (1 << d) compares the bit marked by our bit mask with digits, the collection of previously marked bits.
See the docs on bitwise operators if you want to understand this in detail.
So, if we were to check 626, our numbers would go like this:
________n_____626_______________
|
d | 6
mask | 0001000000
digits | 0000000000
|
________n_____62________________
|
d | 2
mask | 0000000100
digits | 0001000000
|
________n_____6_________________
|
d | 6
mask | 0001000000
digits | 0001000100
^
bit was already set, return false
Solution 1
test using regex
var min = 2;
var max = 7;
res = "";
arr = [81, 35, 22, 45, 49]
arr.push("");
regex=new RegExp("[" + min + "-" + max + "](.)(?!=\1)", "g")
var result = arr.reduce(function(a, b) {
if (regex.test(a)) {
res = res + a + " is true\n"
} else {
res = res + a + " is false\n"
};
return b
});
console.log(res)
The reduce method is different in a sense that it is like a generator function like in python (produces output on the fly)
Its simply loops through each elements in an array using a callback function. I cannot say how efficient is the reduce function.
Nevertheless consider two elements in the array
81 35
^
take this value take the result
and do something from the previous
element and add it
to the result computed
for this element
further information https://msdn.microsoft.com/en-us/library/ff679975%28v=vs.94%29.aspx
SOlution 2
Using list to store value and their boolean
var min = 2;
var max = 7;
res = [""];
arr = [81, 35, 22, 45, 49]
arr.push("");
regex=new RegExp("[" + min + "-" + max + "](.)(?!=\1)", "g")
var result = arr.reduce(function(a, b) {
if (regex.test(a)) {
res.push([a,true])
} else {
res.push([a,false])
};
return b
});
console.log(res)

Guidance to understand Base64 encoding algorithm

I found this algorithm on the net but I'm having a bit of trouble understanding exactly how it works. It encodes an Uint8Array to Base64. I would like to understand especially the sections under the comments "Combine the three bytes into a single integer" and "Use bitmasks to extract 6-bit segments from the triplet". I understood the concept of bit shifting used there, but can't understand what's its purpose in those two sections.
function base64ArrayBuffer(bytes) {
var base64 = ''
var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
var byteLength = bytes.byteLength
var byteRemainder = byteLength % 3
var mainLength = byteLength - byteRemainder
var a, b, c, d
var chunk
// Main loop deals with bytes in chunks of 3
for (var i = 0; i < mainLength; i = i + 3) {
// Combine the three bytes into a single integer
chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]
// Use bitmasks to extract 6-bit segments from the triplet
a = (chunk & 16515072) >> 18 // 16515072 = (2^6 - 1) << 18
b = (chunk & 258048) >> 12 // 258048 = (2^6 - 1) << 12
c = (chunk & 4032) >> 6 // 4032 = (2^6 - 1) << 6
d = chunk & 63 // 63 = 2^6 - 1
// Convert the raw binary segments to the appropriate ASCII encoding
base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d]
}
// Deal with the remaining bytes and padding
if (byteRemainder == 1) {
chunk = bytes[mainLength]
a = (chunk & 252) >> 2 // 252 = (2^6 - 1) << 2
// Set the 4 least significant bits to zero
b = (chunk & 3) << 4 // 3 = 2^2 - 1
base64 += encodings[a] + encodings[b] + '=='
} else if (byteRemainder == 2) {
chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1]
a = (chunk & 64512) >> 10 // 64512 = (2^6 - 1) << 10
b = (chunk & 1008) >> 4 // 1008 = (2^6 - 1) << 4
// Set the 2 least significant bits to zero
c = (chunk & 15) << 2 // 15 = 2^4 - 1
base64 += encodings[a] + encodings[b] + encodings[c] + '='
}
return base64
}
The first step takes each group of 3 bytes in the input and combines them into a 24-bit number. If we call them x = bytes[i], y = bytes[i+1], and z = bytes[i+2], it uses bit-shifting and bit-OR to create a 24-bit integer whose bits are:
xxxxxxxxyyyyyyyyzzzzzzzz
Then it extracts these bits in groups of 6 to get 4 numbers. The bits of a, b, c, and d correspond this way:
xxxxxxxxyyyyyyyyzzzzzzzz
aaaaaabbbbbbccccccdddddd
Then for each of these 6-bit numbers, it indexes the encodings string to get a corresponding character, and concatenates them into the base64 result string.
At the end there are some special cases to deal with the last 1 or 2 bytes in the input if it wasn't a multiple of 3 bytes long.

Converting hexadecimal to float in JavaScript

I would like to convert a number in base 10 with fraction to a number in base 16.
var myno = 28.5;
var convno = myno.toString(16);
alert(convno);
All is well there. Now I want to convert it back to decimal.
But now I cannot write:
var orgno = parseInt(convno, 16);
alert(orgno);
As it doesn't return the decimal part.
And I cannot use parseFloat, since per MDC, the syntax of parseFloat is
parseFloat(str);
It wouldn't have been a problem if I had to convert back to int, since parseInt's syntax is
parseInt(str [, radix]);
So what is an alternative for this?
Disclaimer: I thought it was a trivial question, but googling didn't give me any answers.
This question made me ask the above question.
Another possibility is to parse the digits separately, splitting the string up in two and treating both parts as ints during the conversion and then add them back together.
function parseFloat(str, radix)
{
var parts = str.split(".");
if ( parts.length > 1 )
{
return parseInt(parts[0], radix) + parseInt(parts[1], radix) / Math.pow(radix, parts[1].length);
}
return parseInt(parts[0], radix);
}
var myno = 28.4382;
var convno = myno.toString(16);
var f = parseFloat(convno, 16);
console.log(myno + " -> " + convno + " -> " + f);
Try this.
The string may be raw data (simple text) with four characters (0 - 255) or
a hex string "0xFFFFFFFF" four bytes in length.
jsfiddle.net
var str = '0x3F160008';
function parseFloat(str) {
var float = 0, sign, order, mantissa, exp,
int = 0, multi = 1;
if (/^0x/.exec(str)) {
int = parseInt(str, 16);
}
else {
for (var i = str.length -1; i >=0; i -= 1) {
if (str.charCodeAt(i) > 255) {
console.log('Wrong string parameter');
return false;
}
int += str.charCodeAt(i) * multi;
multi *= 256;
}
}
sign = (int >>> 31) ? -1 : 1;
exp = (int >>> 23 & 0xff) - 127;
mantissa = ((int & 0x7fffff) + 0x800000).toString(2);
for (i=0; i<mantissa.length; i+=1) {
float += parseInt(mantissa[i]) ? Math.pow(2, exp) : 0;
exp--;
}
return float*sign;
}
Please try this:
function hex2dec(hex) {
hex = hex.split(/\./);
var len = hex[1].length;
hex[1] = parseInt(hex[1], 16);
hex[1] *= Math.pow(16, -len);
return parseInt(hex[0], 16) + hex[1];
}
function hex2dec(hex) {
hex = hex.split(/\./);
var len = hex[1].length;
hex[1] = parseInt(hex[1], 16);
hex[1] *= Math.pow(16, -len);
return parseInt(hex[0], 16) + hex[1];
}
// ----------
// TEST
// ----------
function calc(hex) {
let dec = hex2dec(hex);
msg.innerHTML = `dec: <b>${dec}</b><br>hex test: <b>${dec.toString(16)}</b>`
}
let init="bad.a55";
inp.value=init;
calc(init);
<input oninput="calc(this.value)" id="inp" /><div id="msg"></div>
I combined Mark's and Kent's answers to make an overloaded parseFloat function that takes an argument for the radix (much simpler and more versatile):
function parseFloat(string, radix)
{
// Split the string at the decimal point
string = string.split(/\./);
// If there is nothing before the decimal point, make it 0
if (string[0] == '') {
string[0] = "0";
}
// If there was a decimal point & something after it
if (string.length > 1 && string[1] != '') {
var fractionLength = string[1].length;
string[1] = parseInt(string[1], radix);
string[1] *= Math.pow(radix, -fractionLength);
return parseInt(string[0], radix) + string[1];
}
// If there wasn't a decimal point or there was but nothing was after it
return parseInt(string[0], radix);
}
Try this:
Decide how many digits of precision you need after the decimal point.
Multiply your original number by that power of 16 (e.g. 256 if you want two digits).
Convert it as an integer.
Put the decimal point in manually according to what you decided in step 1.
Reverse the steps to convert back.
Take out the decimal point, remembering where it was.
Convert the hex to decimal in integer form.
Divide the result by the the appropriate power of 16 (16^n, where n is the number of digits after the decimal point you took out in step 1).
A simple example:
Convert decimal 23.5 into hex, and want one digit after the decimal point after conversion.
23.5 x 16 = 376.
Converted to hex = 0x178.
Answer in base 16: 17.8
Now convert back to decimal:
Take out the decimal point: 0x178
Convert to decimal: 376
Divide by 16: 23.5
I'm not sure what hexadecimal format you wanted to parse there. Was this something like: "a1.2c"?
Floats are commonly stored in hexadecimal format using the IEEE 754 standard. That standard doesn't use any dots (which don't exist in pure hexadecimal alphabet). Instead of that there are three groups of bits of predefined length (1 + 8 + 23 = 32 bits in total ─ double uses 64 bits).
I've written the following function for parsing such a numbers into float:
function hex2float(num) {
var sign = (num & 0x80000000) ? -1 : 1;
var exponent = ((num >> 23) & 0xff) - 127;
var mantissa = 1 + ((num & 0x7fffff) / 0x7fffff);
return sign * mantissa * Math.pow(2, exponent);
}
Here is a size-improvement of Mark Eirich's answer:
function hex2dec(hex) {
let h = hex.split(/\./);
return ('0x'+h[1])*(16**-h[1].length)+ +('0x'+h[0]);
}
function hex2dec(hex) {
let h = hex.split(/\./);
return ('0x'+h[1])*(16**-h[1].length)+ +('0x'+h[0]);
}
function calc(hex) {
let dec = hex2dec(hex);
msg.innerHTML = `dec: <b>${dec}</b><br>hex test: <b>${dec.toString(16)}</b>`
}
let init = "bad.a55";
inp.value = init;
calc(init);
<input oninput="calc(this.value)" id="inp" /><div id="msg"></div>
private hexStringToFloat(hexString: string): number {
return Buffer.from(hexString, 'hex').readFloatBE(0);
}
Someone might find this useful.
bytes to Float32
function Int2Float32(bytes) {
var sign = (bytes & 0x80000000) ? -1 : 1;
var exponent = ((bytes >> 23) & 0xFF) - 127;
var significand = (bytes & ~(-1 << 23));
if (exponent == 128)
return sign * ((significand) ? Number.NaN : Number.POSITIVE_INFINITY);
if (exponent == -127) {
if (significand === 0) return sign * 0.0;
exponent = -126;
significand /= (1 << 22);
} else significand = (significand | (1 << 23)) / (1 << 23);
return sign * significand * Math.pow(2, exponent);
}

Categories

Resources