最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

python - Javascript - parse string to long - Stack Overflow

programmeradmin3浏览0评论

I have a working script in python doing string to integer conversion based on specified radix using long(16):

modulus=public_key["n"]    
modulusDecoded = long(public_key["n"], 16)

which prints: 8079d7ae567dd2c02dadd1068843136314fa3893fa1fb1ab331682c6a85cad62b208d66c9974bbbb15d52676fd9907efb158c284e96f5c7a4914fd927b7326c40efa14922c68402d05ff53b0e4ccda90bbee5e6c473613e836e2c79da1072e366d0d50933327e77651b6984ddbac1fdecf1fd8fa17e0f0646af662a8065bd873

and 90218878289834622370514047239437874345637539049004160177768047103383444023879266805615186962965710608753937825108429415800005684101842952518531920633990402573136677611127418094912644368840442620417414685225340199872975797295511475162170060618806831021437109054760851445152320452665575790602072479287289305203

respectively. This looks like a Hex to decimal conversion. I tried to have the same result in JS but parseInt() and parseFloat() produce something pletely different. On top of that JavaScript seems not to like chars in input string and sometimes returns NaN.

Could anyone please provide a function / guidance how to get the same functionality as in Python script?

I have a working script in python doing string to integer conversion based on specified radix using long(16):

modulus=public_key["n"]    
modulusDecoded = long(public_key["n"], 16)

which prints: 8079d7ae567dd2c02dadd1068843136314fa3893fa1fb1ab331682c6a85cad62b208d66c9974bbbb15d52676fd9907efb158c284e96f5c7a4914fd927b7326c40efa14922c68402d05ff53b0e4ccda90bbee5e6c473613e836e2c79da1072e366d0d50933327e77651b6984ddbac1fdecf1fd8fa17e0f0646af662a8065bd873

and 90218878289834622370514047239437874345637539049004160177768047103383444023879266805615186962965710608753937825108429415800005684101842952518531920633990402573136677611127418094912644368840442620417414685225340199872975797295511475162170060618806831021437109054760851445152320452665575790602072479287289305203

respectively. This looks like a Hex to decimal conversion. I tried to have the same result in JS but parseInt() and parseFloat() produce something pletely different. On top of that JavaScript seems not to like chars in input string and sometimes returns NaN.

Could anyone please provide a function / guidance how to get the same functionality as in Python script?

Share Improve this question edited Sep 27, 2017 at 12:29 Federico klez Culloca 27.1k17 gold badges59 silver badges100 bronze badges asked Sep 27, 2017 at 12:24 darth0sdarth0s 3203 silver badges14 bronze badges 4
  • I think this is close but it returns floating point... Of course after posting the question I've found almost ready solution here:(danvk/hex2dec.html) – darth0s Commented Sep 27, 2017 at 12:31
  • What is purpose of trying to convert string to number? Why do you not utilize string representation of number? – guest271314 Commented Oct 6, 2017 at 22:32
  • 1 @guest271314 i think the OP was not fully aware of js number precision... – Jonas Wilms Commented Oct 8, 2017 at 10:11
  • @Jonasw yes, you are right. My main problem here was understanding the precision and overflow. – darth0s Commented Oct 9, 2017 at 8:20
Add a ment  | 

3 Answers 3

Reset to default 7

Numbers in JavaScript are floating point so they always lose precision after a certain digit. To have unlimited numbers one could rather use an array of numbers from 0 to 9, which has an unlimited range. To do so based on the hex string input, i do a hex to int array conversion, then I use the double dabble algorithm to convert the array to BCD. That can be printed easily:

const hexToArray = arr => arr.split("").map(n => parseInt(n,16));


const doubleDabble = arr => {
  var l = arr.length;
  for( var b = l * 4; b--;){

    //add && leftshift
    const overflow = arr.reduceRight((carry,n,i) => {

      //apply the >4 +3, then leftshift
      var shifted = ((i < (arr.length - l ) && n>4)?n+3:n ) << 1;

      //just take the right four bits and add the eventual carry value
      arr[i] = (shifted & 0b1111) | carry;

      //carry on
      return shifted > 0b1111;
    }, 0);
    // we've exceeded the current array, lets extend it:
    if(overflow) arr.unshift(overflow);
  }
  return arr.slice(0,-l);
};

const arr = hexToArray("8079d7");
const result = doubleDabble(arr);      
console.log(result.join(""));

Try it

Using the built in api parseInt, you can get upto 100 digts of accuracy on Firefox and 20 digits of accuracy on Chrome.

a = parseInt('8079d7ae567dd2c02dadd1068843136314fa3893fa1fb1ab331682c6a85cad62b208d66c9974bbbb15d52676fd9907efb158c284e96f5c7a4914fd927b7326c40efa14922c68402d05ff53b0e4ccda90bbee5e6c473613e836e2c79da1072e366d0d50933327e77651b6984ddbac1fdecf1fd8fa17e0f0646af662a8065bd873', 16)

a.toPrecision(110)
> Uncaught RangeError: toPrecision() argument must be between 1 and 21

# Chrome
a.toPrecision(20)
"9.0218878289834615508e+307"  

# Firefox
a.toPrecision(100)
"9.021887828983461550807409292694387726882781812072572899692574101215517323445643340153182035092932819e+307"

From the ECMAScript Spec,

  1. Let p be ? ToInteger(precision).
    ...
  2. If p < 1 or p > 100, throw a RangeError exception.

As described in this answer, JavaScript numbers cannot represent integers larger than 9.007199254740991e+15 without loss of precision.

Working with larger integers in JavaScript requires a BigInt library or other special-purpose code, and large integers will then usually be represented as strings or arrays.

Re-using code from this answer helps to convert the hexadecimal number representation

8079d7ae567dd2c02dadd1068843136314fa3893fa1fb1ab331682c6a85cad62b208d66c9974bbbb15d52676fd9907efb158c284e96f5c7a4914fd927b7326c40efa14922c68402d05ff53b0e4ccda90bbee5e6c473613e836e2c79da1072e366d0d50933327e77651b6984ddbac1fdecf1fd8fa17e0f0646af662a8065bd873

to its decimal representation

90218878289834622370514047239437874345637539049004160177768047103383444023879266805615186962965710608753937825108429415800005684101842952518531920633990402573136677611127418094912644368840442620417414685225340199872975797295511475162170060618806831021437109054760851445152320452665575790602072479287289305203

as demonstrated in the following snippet:

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 =
'8079d7ae567dd2c02dadd1068843136314fa389'+
'3fa1fb1ab331682c6a85cad62b208d66c9974bb'+
'bb15d52676fd9907efb158c284e96f5c7a4914f'+
'd927b7326c40efa14922c68402d05ff53b0e4cc'+
'da90bbee5e6c473613e836e2c79da1072e366d0'+
'd50933327e77651b6984ddbac1fdecf1fd8fa17'+
'e0f0646af662a8065bd873';

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

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

//check that it matches the expected output:
console.log('Matches expected:',
  largeIntDecimal === '90218878289834622370514047239437874345637539049'+
    '0041601777680471033834440238792668056151869629657106087539378251084294158000056'+
    '8410184295251853192063399040257313667761112741809491264436884044262041741468522'+
    '5340199872975797295511475162170060618806831021437109054760851445152320452665575'+
    '790602072479287289305203'
);

//check that conversion and back-conversion results in the original number
console.log('Converts back:',
  convertBase(convertBase(largeNumber, 16, 10), 10, 16) === largeNumber
);

发布评论

评论列表(0)

  1. 暂无评论