2011-12-12 11 views
22
function intFromBytes(x){ 
    var val = 0; 
    for (var i = 0; i < x.length; ++i) {   
     val += x[i];   
     if (i < x.length-1) { 
      val = val << 8; 
     } 
    } 
    return val; 
} 

function getInt64Bytes(x){ 
    var bytes = []; 
    var i = 8; 
    do { 
    bytes[--i] = x & (255); 
    x = x>>8; 
    } while (i) 
    return bytes; 
} 

Próbuję przekonwertować numer javascript na tablicę bajtów, a następnie z powrotem na numer. Jednak powyższe funkcje dają nieprawidłowe wyjście o bardzo dużej liczbie.Konwersja javascript Integer na Byte array and back

var array = getInt64Bytes(23423423);  
var value = intFromBytes(array); 

console.log(value); //Prints 23423423 - correct 

var array = getInt64Bytes(45035996273704); 
var value = intFromBytes(array); 

console.log(value); //Prints -1030792152 - incorrect 

To jest moje zrozumienie, że pływaki javascript są 53 bity, więc nie powinna być przepełniona? alert (Math.pow (2,53)) działa dobrze.

+5

Bit zmiany są zawsze wykonywane na podpisanych 32-bitowych liczb całkowitych. – Crozin

+0

To ma sens, niech to będzie odpowiedź, a ja to zaakceptuję. Dzięki –

+0

Jakie jest to obejście? – Justin

Odpowiedz

9

W JavaScript przesunięcia bitów (>>, <<) są zawsze wykonywane na podpisanych, 32-bitowych liczbach całkowitych. Prowadzi to do przekroczenia zakresu dla dużych liczb.

+1

Ale jeśli potrzebna jest długa (64-bitowa liczba całkowita ze znakiem), jakie jest rozwiązanie? –

+0

JS nie obsługuje liczb całkowitych o długości 64 bitów. Zobacz: http://stackoverflow.com/questions/9643626/javascript-cant-handle-64-bit-integers-can-it i http://stackoverflow.com/questions/5353388/javascript-parsing-int64 – Crozin

+0

@ TimoKähkönen 'x << y === x * (2 ** y)' Rozwiązanie z prawej strony może być używane dla 64-bitowych liczb całkowitych. –

2

Wykonanie przesunięcia bitowego jest takie samo jak pomnożenie przez 2^(liczba bitów + 1), więc zamiast przesuwać bity val = val<<8, można po prostu wykonać val = val*256. Sprawdź, czy to działa.

30

Korzystanie wskazówkę dostarczone przez Susanoh13, tutaj są dwie funkcje, które umożliwiają konwersję liczby z/do ByteArray:

longToByteArray = function(/*long*/long) { 
    // we want to represent the input as a 8-bytes array 
    var byteArray = [0, 0, 0, 0, 0, 0, 0, 0]; 

    for (var index = 0; index < byteArray.length; index ++) { 
     var byte = long & 0xff; 
     byteArray [ index ] = byte; 
     long = (long - byte)/256 ; 
    } 

    return byteArray; 
}; 

byteArrayToLong = function(/*byte[]*/byteArray) { 
    var value = 0; 
    for (var i = byteArray.length - 1; i >= 0; i--) { 
     value = (value * 256) + byteArray[i]; 
    } 

    return value; 
}; 
+1

Czasami w byteArrayToLong() byteArray [i] jest traktowany jako ciąg (zależny od przeglądarki), a wynikowa wartość jest obliczana niepoprawnie. Rozwiązałem przez * 1: value = (wartość * 256) + byteArray [i] * 1; – DrArt

+0

Należy określić, czy uważa to bajty za zawierające liczby całkowite ze znakiem lub bez znaku. –

1

brainfuck stylu wersję Lodash. Tylko 4 lulz! nie używaj go!

const uintToArray = (uint, size) => _.chunk(_.padStart(uint, size*2, 0).split(''), 2).map((a)=>parseInt(a[0]+a[1])) 
0
<html> 
<head> 
    <meta charset="utf-8"> 
    <title>Uint32_To_Byte_Array</title> 
    <script> 
    function body_Add(Msg) 
    { 
     document.body.innerHTML = document.body.innerHTML + Msg; 
    } 
    class Byte 
    { 
     constructor(Value) 
     { 
      this.Number = new Uint8Array(1); 
      this.Number[0] = Value; 
     } 
     get Get() 
     { 
      return this.Number[0]; 
     } 
     set Set(newValue) 
     { 
      this.Number[0] = newValue; 
     } 
    }; 
    class Uint32 
    { 
     constructor(Value) 
     { 
      this.Number = new Uint32Array(1); 
      this.Number[0] = Value; 
     } 
     get Get() 
     { 
      return this.Number[0]; 
     } 
     set Set(newValue) 
     { 
      this.Number[0] = newValue; 
     } 
    }; 
    var Conversion = 
    { 
     Uint32_To_Byte_Array: function(Source_Num) 
     { 
      var Uint32_Num = new Uint32(Source_Num); 
      var Byte_Num = new Byte(0); 
      var Byte_Arr = new Uint8Array(4); 
      for (var i = 0; i < 4; i++) 
      { 
       if (Source_Num > 255) 
       { 
        Uint32_Num.Set = Source_Num/256; 
        Byte_Num.Set = Source_Num - Uint32_Num.Get * 256; 
       } 
       else 
       { 
        Byte_Num.Set = Uint32_Num.Get; 
        Uint32_Num.Set = 0; 
       } 
       Byte_Arr[i] = Byte_Num.Get; 
       Source_Num = Uint32_Num.Get; 
      } 
      return(Byte_Arr); 
     }, 
     Byte_Array_To_Uint32: function(Source_Byte_Array, Start_Position) 
     { 
      var Uint32_Num = new Uint32(0); 
      var Multiplier = 1; 
      for (let i = 0; i < 4; i++) 
      { 
       Uint32_Num.Set = Uint32_Num.Get + Source_Byte_Array[Start_Position + i] * Multiplier; 
       Multiplier = Multiplier * 256; 
      } 
      return (Uint32_Num.Get); 
     } 
    }; 
    function Load_Page() 
    { 
     var Numbers = [0,1,257,4294967295]; 
     Numbers.forEach(Convert); 
     function Convert(Item, Index) 
     { 
      var Uint32_Number = Item; 
      var Byte_Array = Conversion.Uint32_To_Byte_Array(Uint32_Number); 
      var Uint32_Number_Restored = Conversion.Byte_Array_To_Uint32(Byte_Array, 0); 
      body_Add("Conversion: Source number: " + Uint32_Number.toString() + ", Byte array: " + Byte_Array.toString() + ", Restored number: " + Uint32_Number_Restored.toString() + "<br>"); 
     }; 
    }; 
    </script> 
</head> 
<body onload="Load_Page()"> 
</body> 

+0

Wynik: Konwersja: Numer źródłowy: 0, Tablica bajtów: 0,0,0,0, Liczba przywrócona: 0; Konwersja: Numer źródłowy: 1, Tablica bajtów: 1,0,0,0, Liczba przywrócona: 1; Konwersja: Numer źródłowy: 257, Tablica bajtów: 1,1,0,0, Liczba przywrócona: 257; Konwersja: Numer źródłowy: 4294967295, Tablica bajtów: 255,255,255,255, przywrócono numer: 4294967295 –