JavaScript pack integers and calculate arbitrary p

2019-02-20 03:27发布

问题:

I need to do the following in JavaScript and so far been unable to find solutions to do it seamlessly:

  • Grab two integers in a specific order and pack them like Python's struct module.
  • This packed value, (bonus for supporting different endianness than host) will be turned into a 64 bit float (double). They must be arbitrary thus I might get an exponent representation of the integer (say, they could be 0xdeadbeef and 500):

    In exp form: 1.0883076389305e-311 1.0883076389305000 * 10 ^ - 311

  • I need to convert it to the arbitrary precision, non-exponent form, so:

    0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000108830763893050000000000000000000000000000000000000000000000000000000000000000000000000000

  • That number converted to a string :)

I haven't found a way to do this in Javascript and I have to output some numbers like that which must support arbitrary precision, or at least, of a scale up to the 1024 exponent (or, say 400) of doubles.

Thanks!!

Note: I do need the "packing/unpacking' to be a faithful representation of those two numbers converted to a double/64bit float. But I don't care about, say, exporting to a string or raw buffer. As long as I get an arbitrary precision double representation for the double it's all fine.

回答1:

1: Khronos has a specification in progress for a DataView interface as part of the WebGL TypedArray requirements, which combined with Int32Array and Float64Array would let you write your two ints into a buffer, and read them back out as a double.

Unfortunately browser support for this isn't common yet - to test your browser visit http://html5test.com/ and look at the section entitled "Native binary data".

Without the TypedArray support above I don't think there's any way to do this using bit-twiddling since Javascript's bit operators treat numbers as 32-bit unsigned values, so you'd have no access to the higher-order bits.

2: double variables don't have any specific form, IEE754 is just an internal representation.

3: that's the point at which you can attempt to show the actual precision. Unfortunately the built-in method, e.g. Number.toFixed(), doesn't support showinng more than 20 decimal places. You will need to parse the exponential form and manually construct a string with the appropriate number of leading zeros.

NB - the exponent range of a double is 2^1024, not 10^1024, hence the real limit is actually ~1.0E±308 - your example figure is smaller than that range.

EDIT actually, there might be a way, but I can't guarantee the precision of this:

  1. take your two integers, call them hi and lo.
  2. extract the exponent - exp = (hi >> 20) & 0x7ff
  3. extract the sign - sign = (hi >> 31)
  4. extract the mantissa - ((hi & 0xfffff) * Math.pow(2, 32) + lo) / Math.pow(2, 52)
  5. result = (1 + m) * (Math.pow(2.0, exp - 1023))
  6. if (sign) result *= -1

EDIT 2 - it works! See http://jsfiddle.net/alnitak/assXS/

var hex2double = function(input) {

    var hi = parseInt(input.substring(0, 8), 16);
    var lo = parseInt(input.substring(8   ), 16);

    var p32 = 0x100000000;
    var p52 = 0x10000000000000;

    var exp = (hi >> 20) & 0x7ff;
    var sign = (hi >> 31);
    var m = 1 + ((hi & 0xfffff) * p32 + lo) / p52;
    m = exp ? (m + 1) : (m * 2.0);

    return (sign ? -1 : 1) * m * Math.pow(2, exp - 1023);
};

Enter a floating point number at http://babbage.cs.qc.edu/IEEE-754/Decimal.html, take the resulting hex string from the bottom row of output, and pass it to the function above. You should see an alert containing the original value.

EDIT 3 code fixed to account for the special case when the exponent bits are all zero.



回答2:

I think you need a big number library for JavaScript such as http://jsfromhell.com/classes/bignumber.