Вычитание unsigned INT в javascript

Хотел написать код на JavaScript, выполняющий то же самое что уже написанный на C++ код. Столкнулся с очень многими нюансами, один из которых это разница в вычитании (и других арифметических операциях) UNSIGNED INT типов.

Например, в С/С++ подобных языках в случае если переменные INT объявлены unsigned.

1 - 115 = 4294967182

std::cout << "1-115: " + std::to_string((unsigned int)1-(unsigned int)115) + "\n"; //выведет: 4294967182

При попытке повторить то же самое на javascript. На javascript результатом вычитания будет:

1-115

-114 или же 114 если взять abs.

С использованием bigInt библиотеки (или без нее) будет 114 (ну или минус 114 если взять abs).

Собственно, моя цель научить javascript работать с unsigned int и при вычитании получать точно такое же значение как получаю в C++ : 4294967182:

с = new bigInt(1);
a = new bigInt(115);
c = c.minus(a).abs();
console.log(c) //114

https://www.quora.com/Can-a-subtraction-give-a-negative-result-using-unsigned-number очень полезная статья, объясняющая почему так происходит.

Операции с UNSGINED INT в javascript — представить число в виде байтов.

Unsigned INT никогда не могут быть негативными. Если размерность числа достигает своего предела, то, как часы, отсчет продолжается с нуля.

Переполнение unsigned INT C++ пример на аналоговых часах

Демонстрация переполнения на примере C++ кода:

unsigned int UINT_MAX = 4294967295; // Maximum value for a variable of type unsigned int. 4294967295 (0xffffffff)
std::cout << UINT_MAX + 1; // will print 0
std::cout << UINT_MAX + 2; // will print 1

Чтобы проводить операции с 4х-байтовыми unsigned INT на javascript, давайте сначала представим каждое число в виде массива из четырех байт. Каждый из 4х байт мы можем получить как:

  1. (n1 >> 24) & 255
  2. (n1 >> 16) & 255
  3. (n1 >> 8) & 255
  4. (n1 >> 0) & 255

Выше валидный javascript синтаксис, используются операторы:

  • >> — right shift operator
  • & — bitwise AND
const n1 = 1 //initial number 1
const n2 = 115 //initial number 2

const bytes1 = [(n1 >> 24) & 255, (n1 >> 16) & 255, (n1 >> 8) & 255, (n1 >> 0) & 255];

const bytes2 = [(n2 >> 24) & 255, (n2 >> 16) & 255, (n2 >> 8) & 255, (n2 >> 0) & 255];

//lets calculate n1 - n2
const res = minus(bytes1, bytes2);

console.log('Result as array of 4 bytes', res);

// обратное преобразование байт в число
console.log('Final subtraction result as number');
console.log((res[0] << 24) + (res[1] << 16) + (res[2] << 8) + (res[3] << 0)); // -114 yeah!

Единственное, чего тут не хватает, это реализации функции minus для [4]byte. Функцию вычитания, принимающая аргументы как массивы байт, может выглядеть вот так:

function minus(a, b) {
    let sub = 0;
    for (let i = 3; i >= 0; i --) {
        a[i] -= b[i] + sub;
        sub = 0;
        if (a[i] < 0) {
            a[i] += 256;
            sub = 1;
        }
    }
    return a;
}

Данный код выполнит обратное преобразование байт в число с использованием left shift (<<) оператора:

(res[0] << 24) + (res[1] << 16) + (res[2] << 8) + (res[3] << 0)

UPD: нужно закончить статью.

 
 
 
 

icon Комментарии 0

Ваш комментарий к статье.. (для авторизованных)

ctrl+enter

icon Вход в систему

зарегистрироваться
НОВЫЕ ПОЛЬЗОВАТЕЛИ