I know that JavaScript can't precisely represent all 64 bit integer numbers. But it can precisely represent numbers larger than 32 bit. And that's what I need. With whatever precision JavaScript can give me.
I have a byte array of known length. It has 1, 2, 4, 8 or 16 bytes. And it can contain a signed or unsigned integer, I know which it is. The data is big-endian (network byte order).
How can I get the number value from that byte array?
There are simple solitions that completely fail on negative numbers. There's DataView that isn't of any help with more than 32 bits. I'm interested in a nice and simple and preferable efficient pure JavaScript solution to handle this. There doesn't seem to be any solution for this in the part of the web that's visible to me.
In case somebody wants to see wrong code, here is my version of positive numbers:
function readInt(array) {
var value = 0;
for (var i = array.length - 1; i >= 0; i--) {
value = (value * 256) + array[i];
}
return value;
}
This page explains a good and simple solution:
Add up all bits from the right end, up to the second most significant bit.
The most significant bit is not added as 2^i but as -2^i.
My code works in a larger scope that has an array and a pos to read from.
function readInt(size) {
var value = 0;
var first = true;
while (size--) {
if (first) {
let byte = array[pos++];
value += byte & 0x7f;
if (byte & 0x80) {
value -= 0x80; // Treat most-significant bit as -2^i instead of 2^i
}
first = false;
}
else {
value *= 256;
value += array[pos++];
}
}
return value;
}
The raw bytes are provided in array (a Uint8Array) and pos is the next index to read. This function starts to read at the current pos and advances pos as it reads one of the size bytes.
Related
I have this function that I found to hash a string, I have been attempting for some hours now to reverse this function to take the hash and return the string. I am not too familiar with left and right shifts, what exactly do they do in the case of this function and would reversing it be even possible? I have used the string "luxor" for my tests and I get "250B0C5E" as the hash but have been unable to get a string back that matches "luxor". I have attempted switching the shifts from left to right and moving the charcodeat but still no success.
function HashString(command) {
let hash = 0;
let string = command.toLowerCase();
for(let i=0; i < string.length; i++) {
let letter = string[i].charCodeAt();
hash = hash + letter;
hash += (hash << 10 >>> 0);
hash ^= (hash >>> 6);
hash = hash >>> 0
}
hash += (hash << 3);
if (hash < 0) {
hash = hash >>> 0
}
hash ^= (hash >>> 11);
hash += (hash << 15);
if (hash < 0) {
hash = hash >>> 0
}
return hash.toString(16).toUpperCase();
}
You can't.
Hashing is a one-way process. When it's a two-way process, it's encryption/decryption. They have very different uses.
This is just a hash function. It takes a string (a series of 16-bit values) and produces a single number (an IEEE-754 double-precision floating point value, a "double") which it then turns into a hex string. But in places during that process, the value is reduced to 32 bits because of the bit shift operators, which convert the double to a 32-bit two's complement integer before doing their work, then convert it back to an equivalent double.
You can't reverse that process, it's lossy (it loses information). There isn't room in a 32-bit value to store the information needed to replicate a string of 16-bit values of any length; it could handle two chars without being lossy, or four if you limit the range to chars where the upper byte of the 16-bit value is 0, but that's it.
I have the following function which I thought would convert very large e.g., 1e+24 and very small, e.g., 1e-18 numbers to a fixed string, e.g., 1000000000000000000000000:
convertExponentialToDecimal (exponentialNumber) {
// Sanity Check - i.e., is it exponential number?
const str = exponentialNumber.toString()
if (str.indexOf('e-') !== -1) {
const exponent = parseInt(str.split('-')[1], 10)
return exponentialNumber.toFixed(exponent)
}
if (str.indexOf('e+') !== -1) {
const exponent = parseInt(str.split('+')[1], 10)
return exponentialNumber.toFixed(exponent)
}
return exponentialNumber
}
However, for very large numbers - the process seems not to be working ...
i.e., a conversion of 1e+24 yields 1e+24, but 1e-18 yields 0.000000000000000001 as expected.
Can anyone spot the obvious issues, or have any pointers or even their own working solution for such a scenario...
If this is any insight - it works for anything less than 1e+21 ...
For your 'very large' part:
if (str.indexOf('e+') !== -1) {
let [a,b] = str.split('+')
a = a.slice(0,-1)
if (a.indexOf('.') !== -1) {
b = parseInt(b) - (a.length - a.indexOf('.') -1)
}
return a.replace('.','')+"".padEnd(b,0)
}
For your 'very small' part (though this would need to be tested, it works on my example but i didn't go through corner cases) :
if (str.indexOf('e-') !== -1) {
const [a,b] = str.split('-')
return '0.'+a.slice(0,-1).padStart(b,0).replace('.','')
}
Number type is IEEE754 float with double precision behind the curtain and it doesn't have enough precision to represent 1e24 digits. If you want to avoid treating numbers as strings, consider BigInt data type.
There are BigInt literals with n suffix and they don't support exponential notation, but luckily they do support **. For big numbers, you can use
10n**24n; // 1000000000000000000000000n
BigInts, are Int, without decimal point. But they are also Big, so you can afford fixed point notation, like first thousand digits are integer part, second thousand digits decimal part (the maximum size depends on available memory).
This may seem obvious, but what is exactly is an extra perfect number? I need to write an algorithm to find extra perfect for a given n, from 1 thru n. Unfortunately, I can't seem to wrap my mind around the question's wording. These are the examples given:
extraPerfect(3) ==> return {1,3}
extraPerfect(7) ==> return {1,3,5,7}
Task:
Given a positive integer N, return the extra perfect numbers in range from 1 to N.
A number is called Extra Perfect Number if it has the same first and last bits (set bits).
Notes:
Only positive integers will be passed.
The returned vector/list should contain the extra perfect numbers in
ascending order (from lowest to highest).
Example #1
extraPerfect(3) ==> return {1,3}
Explanation:
(1)10 = (1)2
First and last bits as set bits.
(3)10 = (11)2
First and last bits as set bits.
Example #2
extraPerfect(7) ==> return {1,3,5,7}
Explanation:
(5)10 = (101)2
First and last bits as set bits.
(7)10 = (111)2
First and last bits as set bits.
It seems to me that an extra perfect number is simply an odd number as, in base 2, it will always start and end with a 1, whereas an even number will always start with a 1 but end with a 0.
Ah now I see I was wrong because I thought it is all about palindroms. However I hope it can be still helpful. That's the code for palindroms in section between 1 to prompt's value.
var exns = (function(){
function dec2bin(dec){
return (dec >>> 0).toString(2);
}
function isEXN(num){
var con = dec2bin(num); // 11011 = 3 + 24 = 27
var accurate = Math.ceil(con.length/2); // 5/2 = 3
var lenmin = con.length-1;
for(var i = 0; i < accurate; i++){
if(con.charAt(i) !== con.charAt(lenmin-i))
return false;
}
return true;
}
var max = parseInt(prompt("Numbers from 1 to ...?"));
var exns = [];
if(!isNaN(max)){
for(var i = 1; i<=max; i++){
if(isEXN(i))
exns.push(i);
}
}
return exns;
})();
Exns should contain array with values.
It looks like extraPerfect should return a list of all numbers less than the argument which have the same first and last digit after converting the decimal argument to binary.
For example:
Decimal - Binary
1 - 1
2 - 10
3 - 11
4 - 100
5 - 101
6 - 110
7 - 111
You'll notice the bold values have the same first and last binary digits.
Some pseudo-code might look like:
function extraPerfect( n ){
var perfects = [];
for(i=0; i<n; i++){
var binary = toBinary(i);
if(binary[0] === binary[binary.length]){
perfects.push(i);
}
}
return perfects;
}
You could pull an algorithm form the pseudo-code.
A Perfect Number is equal to the sum of its positive divisors.
function perfect(num){
for(var i=1,n=0; i<num; i++){
if(num % i === 0){
n += i;
}
}
return n === num;
}
console.log(perfect(6));
console.log(perfect(7));
console.log(perfect(28));
console.log(perfect(8127));
console.log(perfect(8128));
Looking at the int 44 — I need Math.CEIL (log(2) 44) of binary places to represent 44.
(answer is 6 places)
6 places :
___ ___ ___ ___ ___ ___
32 16 8 4 2 1
But how can I check that (for example) the bit of 8 is checked or not ?
A simple solution will be do to :
((1<<3) & 44)>0 so this will check if the bit is set.
But please notice that behind the scenes the computer translates 44 to its binary representation and just check if bit is set via bitwise operation.
Another solution is just to build the binary myself via toString(2) or mod%2 in a loop
Question
Mathematically Via which formula, I can test if n'th bit is set ?
(I would prefer a non loop operation but pure single math phrase)
Divide by the value of the bit that you want to check
and test if the first bit is set (this can be tested with x mod 2 == 1)
Math expression:
floor(value/(2^bitPos)) mod 2 = 1
As JS function:
function isSet(value, bitPos) {
var result = Math.floor(value / Math.pow(2, bitPos)) % 2;
return result == 1;
}
Note: bitPos starts with 0 (bit representing the nr 1)
The 'bit' (actually any base) value of an indexed number index in a value val in base base can in general be calculated as
val = 1966;
index = 2;
base = 10;
alert (Math.floor(val/Math.pow(base,index)) % base);
result: 9
val = 44;
index = 3;
base = 2;
alert (Math.floor(val/Math.pow(base,index)) % base);
result: 1 (only 0 and 1 are possible here – the range will always be 0..base-1).
The combination of Math.floor (to coerce to an integer in Javascript) and Math.pow is kind of iffy here. Even in integer range, Math.pow may generate a floating point number slightly below the expected 'whole' number. Perhaps it is safer to always add a small constant:
alert (Math.floor(0.1+val/Math.pow(base,index)) % base);
You can simply check if the bit at the position is set to 1.
function isBitSet(no, index) {
var bin = no.toString(2);
// Convert to Binary
index = bin.length - index;
// Reverse the index, start from right to left
return bin[index] == 1;
}
isBitSet(44, 2); // Check if second bit is set from left
DEMO
This question already has answers here:
Javascript float comparison
(2 answers)
Closed 6 months ago.
I have this JavaScript function:
Contrl.prototype.EvaluateStatement = function(acVal, cfVal) {
var cv = parseFloat(cfVal).toFixed(2);
var av = parseFloat(acVal).toFixed(2);
if( av < cv) // do some thing
}
When i compare float numbers av=7.00 and cv=12.00 the result of 7.00<12.00 is false!
Any ideas why?
toFixed returns a string, and you are comparing the two resulting strings. Lexically, the 1 in 12 comes before the 7 so 12 < 7.
I guess you want to compare something like:
(Math.round(parseFloat(acVal)*100)/100)
which rounds to two decimals
Compare float numbers with precision:
var precision = 0.001;
if (Math.abs(n1 - n2) <= precision) {
// equal
}
else {
// not equal
}
UPD:
Or, if one of the numbers is precise, compare precision with the relative error
var absoluteError = (Math.abs(nApprox - nExact)),
relativeError = absoluteError / nExact;
return (relativeError <= precision);
The Math.fround() function returns the nearest 32-bit single precision float representation of a Number.
And therefore is one of the best choices to compare 2 floats.
if (Math.fround(1.5) < Math.fround(1.6)) {
console.log('yes')
} else {
console.log('no')
}
>>> yes
// More examples:
console.log(Math.fround(0.9) < Math.fround(1)); >>> true
console.log(Math.fround(1.5) < Math.fround(1.6)); >>> true
console.log(Math.fround(0.005) < Math.fround(0.00006)); >>> false
console.log(Math.fround(0.00000000009) < Math.fround(0.0000000000000009)); >>> false
Comparing floats using short notation, also accepts floats as strings and integers:
var floatOne = 2, floatTwo = '1.456';
Math.floor(floatOne*100) > Math.floor(floatTwo*100)
(!) Note: Comparison happens using integers. What actually happens behind the scenes: 200 > 145
Extend 100 with zero's for more decimal precision. For example use 1000 for 3 decimals precision.
Test:
var floatOne = 2, floatTwo = '1.456';
console.log(Math.floor(floatOne*100), '>', Math.floor(floatTwo*100), '=', Math.floor(floatOne*100) > Math.floor(floatTwo*100));
Comparing of float values is tricky due to long "post dot" tail of the float value stored in the memory. The simplest (and in fact the best) way is: to multiply values, for reducing known amount of post dot digits to zero, and then round the value (to rid of the tail).
Obviously both compared values must be multiplied by the same rate.
F.i.: 1,234 * 1000 gives 1234 - which can be compared very easily. 5,67 can be multiplied by 100, as for reducing the float comparing problem in general, but then it couldn't be compared to the first value (1,234 vel 1234). So in this example it need to be multiplied by 1000.
Then the comparition code could look like (in meta code):
var v1 = 1.234;
var v2 = 5.67;
if (Math.round(v1*1000) < Math.round(v2*1000)) ....