web-dev-qa-db-fra.com

Comment convertir un entier en binaire en JavaScript?

J'aimerais voir des nombres entiers, positifs ou négatifs, en binaire.

Un peu comme cette question , mais pour JavaScript.

252
barlop

Cette réponse tente de traiter les entiers avec des valeurs absolues comprises entre Number.MAX_SAFE_INTEGER (ou 2**53-1) et 2**31. Les solutions actuelles ne traitent que les entiers signés sur 32 bits, mais cette solution générera le complément en deux 64 bits à l'aide de float64ToInt64Binary():

// IIFE to scope internal variables
var float64ToInt64Binary = (function () {
  // create union
  var flt64 = new Float64Array(1)
  var uint16 = new Uint16Array(flt64.buffer)
  // 2**53-1
  var MAX_SAFE = 9007199254740991
  // 2**31
  var MAX_INT32 = 2147483648

  function uint16ToBinary() {
    var bin64 = ''

    // generate padded binary string a Word at a time
    for (var Word = 0; Word < 4; Word++) {
      bin64 = uint16[Word].toString(2).padStart(16, 0) + bin64
    }

    return bin64
  }

  return function float64ToInt64Binary(number) {
    // NaN would pass through Math.abs(number) > MAX_SAFE
    if (!(Math.abs(number) <= MAX_SAFE)) {
      throw new RangeError('Absolute value must be less than 2**53')
    }

    var sign = number < 0 ? 1 : 0

    // shortcut using other answer for sufficiently small range
    if (Math.abs(number) <= MAX_INT32) {
      return (number >>> 0).toString(2).padStart(64, sign)
    }

    // little endian byte ordering
    flt64[0] = number

    // subtract bias from exponent bits
    var exponent = ((uint16[3] & 0x7FF0) >> 4) - 1022

    // encode implicit leading bit of mantissa
    uint16[3] |= 0x10
    // clear exponent and sign bit
    uint16[3] &= 0x1F

    // check sign bit
    if (sign === 1) {
      // apply two's complement
      uint16[0] ^= 0xFFFF
      uint16[1] ^= 0xFFFF
      uint16[2] ^= 0xFFFF
      uint16[3] ^= 0xFFFF
      // propagate carry bit
      for (var Word = 0; Word < 3 && uint16[Word] === 0xFFFF; Word++) {
        // apply integer overflow
        uint16[Word] = 0
      }

      // complete increment
      uint16[Word]++
    }

    // only keep integer part of mantissa
    var bin64 = uint16ToBinary().substr(11, Math.max(exponent, 0))
    // sign-extend binary string
    return bin64.padStart(64, sign)
  }
})()

console.log('8')
console.log(float64ToInt64Binary(8))
console.log('-8')
console.log(float64ToInt64Binary(-8))
console.log('2**33-1')
console.log(float64ToInt64Binary(2**33-1))
console.log('-(2**33-1)')
console.log(float64ToInt64Binary(-(2**33-1)))
console.log('2**53-1')
console.log(float64ToInt64Binary(2**53-1))
console.log('-(2**53-1)')
console.log(float64ToInt64Binary(-(2**53-1)))
console.log('2**52')
console.log(float64ToInt64Binary(2**52))
console.log('-(2**52)')
console.log(float64ToInt64Binary(-(2**52)))
console.log('2**52+1')
console.log(float64ToInt64Binary(2**52+1))
console.log('-(2**52+1)')
console.log(float64ToInt64Binary(-(2**52+1)))
.as-console-wrapper {
  max-height: 100% !important;
}

Cette réponse traite principalement du format à virgule flottante double précision IEEE-754 , illustré ici:

IEEE-754 Double-precision floating-point format

   seee eeee eeee ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff
   ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
   [    uint16[3]    ] [    uint16[2]    ] [    uint16[1]    ] [    uint16[0]    ]
   [                                   flt64[0]                                  ]

   little endian byte ordering

   s = sign = uint16[3] >> 15
   e = exponent = (uint16[3] & 0x7FF) >> 4
   f = fraction

La solution consiste à créer une union entre un nombre à virgule flottante de 64 bits et un tableau d'entiers non signés de 16 bits dans un ordre d'octet peu significatif. Après avoir validé la plage d'entrée entière, il convertit l'entrée en un nombre à virgule flottante à double précision dans la mémoire tampon, puis utilise l'union pour obtenir un accès bit à la valeur et calcule la chaîne binaire sur la base des bits d'exposant et de fraction binaires non biaisés.

La solution est implémentée dans ECMAScript 5 pur sauf pour l’utilisation de String#padStart() , qui a n polyfill disponible ici .

24
Patrick Roberts
_function dec2bin(dec){
    return (dec >>> 0).toString(2);
}

dec2bin(1);    // 1
dec2bin(-1);   // 11111111111111111111111111111111
dec2bin(256);  // 100000000
dec2bin(-256); // 11111111111111111111111100000000
_

Vous pouvez utiliser la fonction Number.toString(2) , mais la représentation de nombres négatifs pose quelques problèmes. Par exemple, _(-1).toString(2)_ sortie est _"-1"_.

Pour résoudre ce problème, vous pouvez utiliser l'opérateur de bits non signé de décalage à droite ( >>> ) pour contraindre votre nombre à un entier non signé.

Si vous exécutez _(-1 >>> 0).toString(2)_, vous décalerez votre nombre 0 bits vers la droite, ce qui ne changera pas le nombre lui-même, mais il sera représenté par un entier non signé. Le code ci-dessus générera _"11111111111111111111111111111111"_ correctement.

Cette question a plus d'explications.

_-3 >>> 0_ (décalage logique de droite) convertit ses arguments en entiers non signés, raison pour laquelle vous obtenez la représentation du complément à deux de 32 bits de -3.

429
fernandosavio

Essayer

num.toString(2);

Le 2 est le radix et peut être n’importe quelle base entre 2 et 36

source ici

UPDATE:

Cela ne fonctionnera que pour les nombres positifs, Javascript représente des entiers binaires négatifs en notation à complément à deux. J'ai créé cette petite fonction qui devrait faire l'affaire, je ne l'ai pas testée correctement:

function dec2Bin(dec)
{
    if(dec >= 0) {
        return dec.toString(2);
    }
    else {
        /* Here you could represent the number in 2s compliment but this is not what 
           JS uses as its not sure how many bits are in your number range. There are 
           some suggestions https://stackoverflow.com/questions/10936600/javascript-decimal-to-binary-64-bit 
        */
        return (~dec).toString(2);
    }
}

J'ai eu de l'aide de ici

182
Manatok

Le binaire in 'convertir en binaire' peut faire référence à trois choses principales. Le système de numéro de position, la représentation binaire en mémoire ou les chaînes de bits 32 bits. (pour les chaînes de bits 64 bits, voir réponse de Patrick Roberts )

1. Système de numération

(123456).toString(2) convertira les nombres en base 2 système de numération de position . Dans ce système, les nombres négatifs sont écrits avec des signes moins, tout comme en décimal.

2. Représentation interne

La représentation interne des nombres est virgule flottante 64 bits et certaines limitations sont décrites dans cette réponse . Il n'y a aucun moyen simple de créer une représentation sous forme de chaîne de bits en javascript, ni d'accéder à des bits spécifiques.

3. Masques et opérateurs au niveau des bits

MDN a un bon aperç du fonctionnement des opérateurs au niveau du bit. Important:

Les opérateurs au niveau des bits traitent leurs opérandes comme une séquence de 32 bits (zéros et uns)

Avant que les opérations ne soient appliquées, les nombres à virgule flottante 64 bits sont convertis en entiers signés 32 bits. Après qu'ils soient reconvertis.

Voici l'exemple de code MDN permettant de convertir des nombres en chaînes de 32 bits.

function createBinaryString (nMask) {
  // nMask must be between -2147483648 and 2147483647
  for (var nFlag = 0, nShifted = nMask, sMask = ""; nFlag < 32;
       nFlag++, sMask += String(nShifted >>> 31), nShifted <<= 1);
  return sMask;
}

createBinaryString(0) //-> "00000000000000000000000000000000"
createBinaryString(123) //-> "00000000000000000000000001111011"
createBinaryString(-1) //-> "11111111111111111111111111111111"
createBinaryString(-1123456) //-> "11111111111011101101101110000000"
createBinaryString(0x7fffffff) //-> "01111111111111111111111111111111"
47
Annan

Un moyen simple est juste ...

Number(42).toString(2);

// "101010"
39
ad rees

Remarque: le (x>>>0).toString(2); de base présente un léger problème lorsque x est positif. J'ai un exemple de code à la fin de ma réponse qui corrige ce problème avec la méthode >>> tout en continuant d'utiliser >>>.

(-3>>>0).toString(2);

prints -3 in 2s complement.

1111111111101

Un exemple de travail

C:\>type n1.js
console.log(   (-3 >>> 0).toString(2)    );
C:\>
C:\>node n1.js
11111111111111111111111111111101

C:\>

Ceci dans la barre d'URL est une autre preuve rapide

javascript:alert((-3>>>0).toString(2))

Remarque: le résultat est très légèrement erroné, en ce sens qu'il commence toujours par un 1, ce qui est correct pour les nombres négatifs. Pour les nombres positifs, vous devez ajouter un 0 au début, afin que le résultat soit vraiment complémentaire de 2s. Ainsi, (8>>>0).toString(2) produit 1000 qui n'est pas vraiment un complément 8 en 2, mais une valeur 0, ce qui en fait 01000, correspond au complément 8 en 2. En complément 2 correct, toute chaîne de bits commençant par 0 est> = 0, et toute chaîne de bits commençant par 1 est négative.

par exemple. cela contourne ce problème

// or x=-5  whatever number you want to view in binary  
x=5;   
if(x>0) prepend="0"; else prepend=""; 
alert(prepend+((x>>>0)).toString(2));

Les autres solutions sont celles d’Annan (bien que les explications et les définitions d’Annan soient pleines d’erreurs, il a un code qui produit le bon résultat) et la solution de Patrick.

Quiconque ne comprend pas le fait que les nombres positifs commencent par 0 et les nombres négatifs par 1, en complément à 2, peut vérifier ce complément SO QnA sur 2s. Qu'est-ce que le "Complément 2"?

10
barlop

Vous pouvez écrire votre propre fonction qui retourne un tableau de bits. Exemple comment convertir un nombre en bits

Diviseur | Dividende | bits/reste

2 | 9 | 1

2 | 4 | 0

2 | 2 | 0

~ | 1 | ~

exemple de la ligne ci-dessus: 2 * 4 = 8 et le reste est 1 donc 9 = 1 0 0 1

function numToBit(num){
    var number = num
    var result = []
    while(number >= 1 ){
        result.unshift(Math.floor(number%2))
        number = number/2
    }
    return result
}

Lire les restes de bas en haut. Chiffre 1 au milieu en haut.

6
supritshah1289

J'ai utilisé une approche différente pour proposer quelque chose qui fait cela. J'ai décidé de ne pas utiliser ce code dans mon projet, mais je pensais le laisser ailleurs, au cas où il serait utile à quelqu'un.

  • N'utilise pas la contrainte de transfert de bits ou de complément à deux.
  • Vous choisissez le nombre de bits qui sortent (il vérifie les valeurs valides de "8", "16", "32", mais je suppose que vous pouvez changer cela)
  • Vous choisissez de le traiter comme un entier signé ou non signé.
  • Il recherchera les problèmes de plage en fonction de la combinaison de signature/non signé et du nombre de bits, mais vous souhaiterez améliorer la gestion des erreurs.
  • Il possède également la version "inversée" de la fonction qui reconvertit les bits en int. Vous en aurez besoin puisqu'il n'y a probablement rien d'autre qui puisse interpréter cette sortie: D
function intToBitString(input, size, unsigned) {
        if ([8, 16, 32].indexOf(size) == -1) {
                throw "invalid params";
        }
        var min = unsigned ? 0 : - (2 ** size / 2);
        var limit = unsigned ? 2 ** size : 2 ** size / 2;
        if (!Number.isInteger(input) || input < min || input >= limit) {
                throw "out of range or not an int";
        }
        if (!unsigned) {
                input += limit;
        }
        var binary = input.toString(2).replace(/^-/, '');
        return binary.padStart(size, '0');
}

function bitStringToInt(input, size, unsigned) {
        if ([8, 16, 32].indexOf(size) == -1) {
                throw "invalid params";
        }
        input = parseInt(input, 2);
        if (!unsigned) {
                input -= 2 ** size / 2;
        }
        return input;
}


// EXAMPLES

var res;
console.log("(uint8)10");
res = intToBitString(10, 8, true);
console.log("intToBitString(res, 8, true)");
console.log(res);
console.log("reverse:", bitStringToInt(res, 8, true));
console.log("---");

console.log("(uint8)127");
res = intToBitString(127, 8, true);
console.log("intToBitString(res, 8, true)");
console.log(res);
console.log("reverse:", bitStringToInt(res, 8, true));
console.log("---");

console.log("(int8)127");
res = intToBitString(127, 8, false);
console.log("intToBitString(res, 8, false)");
console.log(res);
console.log("reverse:", bitStringToInt(res, 8, false));
console.log("---");

console.log("(int8)-128");
res = intToBitString(-128, 8, false);
console.log("intToBitString(res, 8, true)");
console.log(res);
console.log("reverse:", bitStringToInt(res, 8, true));
console.log("---");

console.log("(uint16)5000");
res = intToBitString(5000, 16, true);
console.log("intToBitString(res, 16, true)");
console.log(res);
console.log("reverse:", bitStringToInt(res, 16, true));
console.log("---");

console.log("(uint32)5000");
res = intToBitString(5000, 32, true);
console.log("intToBitString(res, 32, true)");
console.log(res);
console.log("reverse:", bitStringToInt(res, 32, true));
console.log("---");
0
braks