将大数字从二进制转换为十进制并返回JavaScript

LJ *_*ski 5 javascript

我在JavaScript中有一个非常大的数字表示为二进制:

 var largeNumber = '11010011010110100001010011111010010111011111000010010111000111110011111011111000001100000110000011000001100111010100111010101110100010001011010101110011110000011000001100000110000011001001100000110000011000001100000110000111000011100000110000011000001100000110000011000010101100011001110101101001100110100100000110000011000001100000110001001101011110110010001011010001101011010100011001001110001110010100111011011111010000110001110010101010001111010010000101100001000001100001011000011011111000011110001110111110011111111000100011110110101000101100000110000011000001100000110000011010011101010110101101001111101001010010111101011000011101100110010011001001111101'
Run Code Online (Sandbox Code Playgroud)

当我通过使用parseInt(largeNumber, 10)l 将其转换为十进制时它给了我1.5798770299367407e+199但是当我尝试将其转换回二进制时:

parseInt(`1.5798770299367407e+199`, 2)
Run Code Online (Sandbox Code Playgroud)

当我期望看到我的原始二进制表示时,它返回1(我认为与parseInt舍入值的工作方式有关)largeNumber.你能解释一下这种行为吗?我如何在JavaScript中将其转换回原始状态?

编辑:这个问题是我的实验结果,我正在玩存储和传输大量的布尔数据.它largeNumber是一组[true,true,false,true ...]布尔值的表示,必须在客户端,客户端工作者和服务器之间共享.

Far*_*her 7

BigInt内置于js中

function parseBigInt(str, base=10) {
  base = BigInt(base)
  var bigint = BigInt(0)
  for (var i = 0; i < str.length; i++) {
    var code = str[str.length-1-i].charCodeAt(0) - 48; if(code >= 10) code -= 39
    bigint += base**BigInt(i) * BigInt(code)
  }
  return bigint
}
Run Code Online (Sandbox Code Playgroud)
parseBigInt('11010011010110100001010011111010010111011111000010010111000111110011111011111000001100000110000011000001100111010100111010101110100010001011010101110011110000011000001100000110000011001001100000110000011000001100000110000111000011100000110000011000001100000110000011000010101100011001110101101001100110100100000110000011000001100000110001001101011110110010001011010001101011010100011001001110001110010100111011011111010000110001110010101010001111010010000101100001000001100001011000011011111000011110001110111110011111111000100011110110101000101100000110000011000001100000110000011010011101010110101101001111101001010010111101011000011101100110010011001001111101', 2)
// 15798770299367407029725345423297491683306908462684165669735033278996876231474309788453071122111686268816862247538905966252886886438931450432740640141331094589505960171298398097197475262433234991526525n
Run Code Online (Sandbox Code Playgroud)

  • 请注意,使用“BigInt”,可以使用单个表达式“BigInt('0b' + str)”来解决OP。 (7认同)

Tom*_*aas 6

正如Andrew L.的回答以及几位评论者所指出的那样,largeNumber超出JavaScript可以表示为普通数字的整数而不会损失精度 - 即 9.007199254740991e + 15.

如果要使用更大的整数,则需要BigInt库或其他专用代码.

下面是一些代码,演示如何在不同的基本表示之间转换任意大的正整数,表明你的确切十进制表示largeNumber

15 798 770 299 367 407 029 725 345 423 297 491 683 306 908 462 684 165 669 735 033 278 996 876 231 474 309 788 453 071 122 111 686 268 816 862 247 538 905 966 252 886 886 438 931 450 432 740 640 141 331 094 589 505 960 171 298 398 097 197 475 262 433 234 991 526 525

function parseBigInt(bigint, base) {
  //convert bigint string to array of digit values
  for (var values = [], i = 0; i < bigint.length; i++) {
    values[i] = parseInt(bigint.charAt(i), base);
  }
  return values;
}

function formatBigInt(values, base) {
  //convert array of digit values to bigint string
  for (var bigint = '', i = 0; i < values.length; i++) {
    bigint += values[i].toString(base);
  }
  return bigint;
}

function convertBase(bigint, inputBase, outputBase) {
  //takes a bigint string and converts to different base
  var inputValues = parseBigInt(bigint, inputBase),
    outputValues = [], //output array, little-endian/lsd order
    remainder,
    len = inputValues.length,
    pos = 0,
    i;
  while (pos < len) { //while digits left in input array
    remainder = 0; //set remainder to 0
    for (i = pos; i < len; i++) {
      //long integer division of input values divided by output base
      //remainder is added to output array
      remainder = inputValues[i] + remainder * inputBase;
      inputValues[i] = Math.floor(remainder / outputBase);
      remainder -= inputValues[i] * outputBase;
      if (inputValues[i] == 0 && i == pos) {
        pos++;
      }
    }
    outputValues.push(remainder);
  }
  outputValues.reverse(); //transform to big-endian/msd order
  return formatBigInt(outputValues, outputBase);
}

var largeNumber =
  '1101001101011010000101001111101001011101' + 
  '1111000010010111000111110011111011111000' +
  '0011000001100000110000011001110101001110' +
  '1010111010001000101101010111001111000001' +
  '1000001100000110000011001001100000110000' +
  '0110000011000001100001110000111000001100' +
  '0001100000110000011000001100001010110001' +
  '1001110101101001100110100100000110000011' +
  '0000011000001100010011010111101100100010' +
  '1101000110101101010001100100111000111001' +
  '0100111011011111010000110001110010101010' +
  '0011110100100001011000010000011000010110' +
  '0001101111100001111000111011111001111111' +
  '1000100011110110101000101100000110000011' +
  '0000011000001100000110100111010101101011' +
  '0100111110100101001011110101100001110110' +
  '0110010011001001111101';

//convert largeNumber from base 2 to base 10
var largeIntDecimal = convertBase(largeNumber, 2, 10);


function groupDigits(bigint){//3-digit grouping
  return bigint.replace(/(\d)(?=(\d{3})+$)/g, "$1 ");
}

//show decimal result in console:
console.log(groupDigits(largeIntDecimal));

//converting back to base 2:
var restoredOriginal = convertBase(largeIntDecimal, 10, 2);

//check that it matches the original:
console.log(restoredOriginal === largeNumber);
Run Code Online (Sandbox Code Playgroud)


Li3*_*357 5

当您将其转换回二进制时,您不会将其解析为基数 2,这是错误的。您还尝试将整数解析为浮点数,这可能会导致不精确。有了这一行:

parseInt(`1.5798770299367407e+199`, 2)
Run Code Online (Sandbox Code Playgroud)

你告诉 JS 将基数 10 解析为基数 2!您需要做的是将其转换为二进制文件,如下所示(注意 的使用parseFloat):

parseInt(`1.5798770299367407e+199`, 2)
Run Code Online (Sandbox Code Playgroud)

之前,您将十进制转换为二进制。您需要做的就是调用toString(radix)将其转换回二进制,因此:

var binaryRepresentation = integerFormOfLargeNumber.toString(2);
Run Code Online (Sandbox Code Playgroud)

如果查看输出,您会看到:

Infinity
Infinity
Run Code Online (Sandbox Code Playgroud)

由于您的二进制数非常大,因此可能会影响结果。因为JS最多支持64位,所以这个数字太大了。它导致Infinity并且不精确。如果您尝试将二进制重新转换largeNumberConvert为十进制,如下所示:

parseInt(largeNumberConvert, 10);
Run Code Online (Sandbox Code Playgroud)

可以看到它输出了Infinity.

  • “*告诉 JS 将基数 10 解析为基数 2!*” - 实际上比这更糟糕。他告诉我们将科学记数法中的浮点数*解析为整数*。 (2认同)

Luk*_*one 5

如果您要传输大量二进制数据,则应使用 BigInt。BigInt 允许您表示任意数量的位。

// parse large number from string
let numString = '1101001101011010000101001111101001011101111100001001'

// as number
let num = BigInt('0b' + numString)

// now num holds large number equivalent to numString
console.log(num)  // 3718141639515913n

// print as base 2
console.log(num.toString(2))  // 1101001101011010000101001111101001011101111100001001
Run Code Online (Sandbox Code Playgroud)

辅助函数

// some helper functions

// get kth bit from right
function getKthBit(x, k){
  return (x & (1n << k)) >> k;
}

// set kth bit from right to 1
function setKthBit(x, k){
  return (1n << k) | x;
}

// set kth bit from right to 0
function unsetKthBit(x, k){
  return (x & ~(1n << k));
}

getKthBit(num, 0n);  
// 1n

getKthBit(num, 5n);  
// 0n

setKthBit(num, 1n).toString(2); 
// 1101001101011010000101001111101001011101111100001011

setKthBit(num, 4n); 
// 1101001101011010000101001111101001011101111100011001

unsetKthBit(num, 0n).toString(2);
// 1101001101011010000101001111101001011101111100001000

unsetKthBit(num, 0n).toString(2);
// 1101001101011010000101001111101001011101111100000001
Run Code Online (Sandbox Code Playgroud)

为方便起见,如果您要序列化回客户端,您可能希望将此添加到 BigInt。然后您可以将其作为字符串读回。否则你会得到“Uncaught TypeError: Do not know how to serialize a BigInt”,因为出于某种原因Javascript Object Notation不知道如何序列化Javascript中的一种类型。

    Object.defineProperty(BigInt.prototype, "toJSON", {
        get() {
            "use strict";
            return () => this.toString() + 'n';
        }
    });
Run Code Online (Sandbox Code Playgroud)