Педро уже ответил на это, но так как это хак и не совсем интуитивно, я объясню это.
Я выполняю побитовые операции, результат которых, очевидно, сохраняется как двадополнить номер. При наведении курсора на переменную, хранящуюся в ней, я вижу num = -2086528968
Нет, результатом большинства битовых операций является 32-битное знаковое целое число. Это означает, что бит 0x80000000
интерпретируется как знак, за которым следует 31 бит значения.
Странная битовая последовательность из-за того, как JS строковое выравнивает значение, что-то вроде sign + Math.abs(value).toString(base)
;
Как с этим бороться? Нам нужно указать JS не интерпретировать этот бит как знак, а как часть значения. Но как?
Простым для понимания решением было бы добавить 0x100000000
к отрицательным числам и, следовательно, получить их положительные двойники.
function print(value) {
if (value < 0) {
value += 0x100000000;
}
console.log(value.toString(2).padStart(32, 0));
}
print(-2086528968);
Другим способом было бы преобразование нижнего и верхнего битов отдельно
function print(value) {
var signBit = value < 0 ? "1" : "0";
var valueBits = (value & 0x7FFFFFFF).toString(2);
console.log(signBit + valueBits.padStart(31, 0));
}
print(-2086528968);
//or lower and upper half of the bits:
function print2(value) {
var upperHalf = (value >> 16 & 0xFFFF).toString(2);
var lowerHalf = (value & 0xFFFF).toString(2);
console.log(upperHalf.padStart(16, 0) + lowerHalf.padStart(16, 0));
}
print2(-2086528968);
Другой способ связан с «взломом», который использует Педро. Вы помните, как я сказал, что большинство битовых операций возвращают int32
? Есть одна операция, которая на самом деле возвращает беззнаковое (32-битное) интергер, так называемое смещение вправо с нулевым заполнением .
Итак number >>> 0
не изменяет биты числа, но первый бит больше не интерпретируется как знак.
function uint32(value){
return value>>>0;
}
function print(value){
console.log(uint32(value).toString(2).padStart(32, 0));
}
print(-2086528968);
Буду ли я запускать этот код переключения только тогда, когда число отрицательное или всегда?
Вообще говоря, вреда нетпри выполнении nr >>> 0
над положительными целыми числами, но будьте осторожны, чтобы не переусердствовать.
Технически JS поддерживает только числа, которые являются double
значениями (64bit floating point
значениями) . Внутренне двигатели также используют значения int32
;где возможно. Но нет uint32
значений. Поэтому, когда вы конвертируете ваш отрицательный int32
в uint32
, движок преобразует его в double
. И если вы выполняете еще одну битовую операцию, первое, что она делает, - конвертирует ее обратно.
Так что это нормально делать, например, когда вам нужно фактическое значение uint32
, например, напечатать биты здесь, ноВы должны избегать этого преобразования между операциями. Как "просто чтобы исправить это".