admin管理员组

文章数量:1022843

I have JavaScript code that retrieves numerical vectors from a web-service. The original data is an array of doubles that is converted to a byte array and then base64 encoded. I decode from base64 in JavaScript, but then I don't know how to transform the resulting bytes into an array of numbers.

I have JavaScript code that retrieves numerical vectors from a web-service. The original data is an array of doubles that is converted to a byte array and then base64 encoded. I decode from base64 in JavaScript, but then I don't know how to transform the resulting bytes into an array of numbers.

Share Improve this question asked Dec 2, 2011 at 18:46 AbielAbiel 5,48511 gold badges58 silver badges82 bronze badges 8
  • I'm not sure what your data looks like, but you can make an array from delimited data using .split("delimiterCharacter") – Diodeus - James MacFarlane Commented Dec 2, 2011 at 18:49
  • Uh, double data as byte sequence - I think, you'll have to implement this manually. In this question I found an algorithm to convert a double into bytes, maybe you can reverse it. – Yogu Commented Dec 2, 2011 at 18:51
  • 2 Can you provide some sample data? – Alec Gorge Commented Dec 2, 2011 at 18:51
  • @alecgorge Here is what would be printed with console.log() after base64 decoding: l²@ù±@*±@±@Ó°@¾¯@â®@&®@ ­@­@©@ ©@¶¨@Æ©@À§@V©@ä§@²¨@¬§@ʧ@Ч@§@²©@Ú¨@¥@©@¶§@À¥@¦@L¦@è¦@¦@ª¦@¦@§@§@(§@N¨@~¨@¨@©@ª@¨@l«@Vª@îª@¦«@¨@D«@v«@4«@à«@ª­@«@­@r­@þ¬@,®@b®@Ư@¯@Ø®@Ì®@D°@n°@,°@Ø®@æ¬@ȯ@1°@|°@h°@h°@v°@z¯@¾°@r°@̯@·°@Я@ü¯@â¯@¯@¯@z®@ö®@¬@j¬@°©@>«@d©@¨@¨@H¥@À¤@î¤@¤@¡@Æ¢@Ê @Ø@* @T @@@@Ü @Ä@@0@@Þ @¡@¸¢@î¢@¢@¨£@ø£@ú¢@¤@¤@£@ä¢@¥@Ò¥@¤@J¥@&¦@¨¦@ – Abiel Commented Dec 2, 2011 at 19:10
  • @Abiel That is a bit unwieldy. How about the base64 encoded data in a gist? – Alec Gorge Commented Dec 2, 2011 at 19:11
 |  Show 3 more ments

2 Answers 2

Reset to default 4

This was the only way I could think of off the top of my head to do it.

function bytesToDouble(str,start) {
    start *= 8;
    var data = [str.charCodeAt(start+7),
                str.charCodeAt(start+6),
                str.charCodeAt(start+5),
                str.charCodeAt(start+4),
                str.charCodeAt(start+3),
                str.charCodeAt(start+2),
                str.charCodeAt(start+1),
                str.charCodeAt(start+0)];

    var sign = (data[0] & 1<<7)>>7;

    var exponent = (((data[0] & 127) << 4) | (data[1]&(15<<4))>>4);

    if(exponent == 0) return 0;
    if(exponent == 0x7ff) return (sign) ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY;

    var mul = Math.pow(2,exponent - 1023 - 52);
    var mantissa = data[7]+
        data[6]*Math.pow(2,8*1)+
        data[5]*Math.pow(2,8*2)+
        data[4]*Math.pow(2,8*3)+
        data[3]*Math.pow(2,8*4)+
        data[2]*Math.pow(2,8*5)+
        (data[1]&15)*Math.pow(2,8*6)+
        Math.pow(2,52);

    return Math.pow(-1,sign)*mantissa*mul;
}

var data = atob("AAAAAABsskAAAAAAAPmxQAAAAAAAKrF");

alert(bytesToDouble(data,0)); // 4716.0
alert(bytesToDouble(data,1)); // 4601.0

This should give you a push in the right direction, though it took me a while to remember how to deal with doubles.

One big caveats to note though:

This relies on the atob to do the base64 decoding, which is not supported everywhere, and aside from that probably isn't a great idea anyway. What you really want to do is unroll the base64 encoded string to an array of numbers (bytes would be the easiest to work with although not the most efficient thing on the planet). The reason is that when atob does its magic, it returns a string, which is far from ideal. Depending on the encoding the code points it maps to (especially for code points between 128 and 255) the resulting .charCodeAt() may not return what you expect.

And there may be some accuracy issues, because after all I am using a double to calculate a double, but I think it might be okay.

Base64 is fairly trivial to work with, so you should be able to figure that part out.

If you did switch to an array (rather than the str string now), then you would obviously drop the .charCodeAt() reference and just get the indices you want directly.

There is a functioning fiddle here

I assume we have used this function in web service (c#) to encode the double array data as string:

//Input: [552.4, 539.8]
//Output: IOz0gCAsscA=

private string ConvertToSerializableString(double[] input)
{
  byte[] data = new byte[input.Length * 4];
  for (int i = 0; i < input.Length; i++)
  {
    int source = (int)(input[i] * 1E6);    
    int dataIndex = i * 4;
    data[dataIndex] = (byte)((source >> 24) & 0xFF);
    data[dataIndex + 1] = (byte)((source >> 16) & 0xFF);
    data[dataIndex + 2] = (byte)((source >> 8) & 0xFF);
    data[dataIndex + 3] = (byte)(source & 0xFF);
  }

  return Convert.ToBase64String(data);          
}

Then we can use the following client script (javascript) to decode it:

var base64EncodedDoubleArrayData = "IOz0gCAsscA=";
var byteData = window.atob(base64EncodedDoubleArrayData);                

var doubleArray = [];
for (var iColumn = 0; iColumn < byteData.length; iColumn = iColumn + 4) 
{
   var item = (byteData.charCodeAt(iColumn) << 24) + (byteData.charCodeAt(iColumn + 1) << 16) + (byteData.charCodeAt(iColumn + 2) << 8) + byteData.charCodeAt(iColumn + 3);   
   var doubleResult = parseFloat(item/1e6);
   doubleArray.push(doubleResult);
}  

//it should return something like doubleArray = [552.4, 539.8]

I have JavaScript code that retrieves numerical vectors from a web-service. The original data is an array of doubles that is converted to a byte array and then base64 encoded. I decode from base64 in JavaScript, but then I don't know how to transform the resulting bytes into an array of numbers.

I have JavaScript code that retrieves numerical vectors from a web-service. The original data is an array of doubles that is converted to a byte array and then base64 encoded. I decode from base64 in JavaScript, but then I don't know how to transform the resulting bytes into an array of numbers.

Share Improve this question asked Dec 2, 2011 at 18:46 AbielAbiel 5,48511 gold badges58 silver badges82 bronze badges 8
  • I'm not sure what your data looks like, but you can make an array from delimited data using .split("delimiterCharacter") – Diodeus - James MacFarlane Commented Dec 2, 2011 at 18:49
  • Uh, double data as byte sequence - I think, you'll have to implement this manually. In this question I found an algorithm to convert a double into bytes, maybe you can reverse it. – Yogu Commented Dec 2, 2011 at 18:51
  • 2 Can you provide some sample data? – Alec Gorge Commented Dec 2, 2011 at 18:51
  • @alecgorge Here is what would be printed with console.log() after base64 decoding: l²@ù±@*±@±@Ó°@¾¯@â®@&®@ ­@­@©@ ©@¶¨@Æ©@À§@V©@ä§@²¨@¬§@ʧ@Ч@§@²©@Ú¨@¥@©@¶§@À¥@¦@L¦@è¦@¦@ª¦@¦@§@§@(§@N¨@~¨@¨@©@ª@¨@l«@Vª@îª@¦«@¨@D«@v«@4«@à«@ª­@«@­@r­@þ¬@,®@b®@Ư@¯@Ø®@Ì®@D°@n°@,°@Ø®@æ¬@ȯ@1°@|°@h°@h°@v°@z¯@¾°@r°@̯@·°@Я@ü¯@â¯@¯@¯@z®@ö®@¬@j¬@°©@>«@d©@¨@¨@H¥@À¤@î¤@¤@¡@Æ¢@Ê @Ø@* @T @@@@Ü @Ä@@0@@Þ @¡@¸¢@î¢@¢@¨£@ø£@ú¢@¤@¤@£@ä¢@¥@Ò¥@¤@J¥@&¦@¨¦@ – Abiel Commented Dec 2, 2011 at 19:10
  • @Abiel That is a bit unwieldy. How about the base64 encoded data in a gist? – Alec Gorge Commented Dec 2, 2011 at 19:11
 |  Show 3 more ments

2 Answers 2

Reset to default 4

This was the only way I could think of off the top of my head to do it.

function bytesToDouble(str,start) {
    start *= 8;
    var data = [str.charCodeAt(start+7),
                str.charCodeAt(start+6),
                str.charCodeAt(start+5),
                str.charCodeAt(start+4),
                str.charCodeAt(start+3),
                str.charCodeAt(start+2),
                str.charCodeAt(start+1),
                str.charCodeAt(start+0)];

    var sign = (data[0] & 1<<7)>>7;

    var exponent = (((data[0] & 127) << 4) | (data[1]&(15<<4))>>4);

    if(exponent == 0) return 0;
    if(exponent == 0x7ff) return (sign) ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY;

    var mul = Math.pow(2,exponent - 1023 - 52);
    var mantissa = data[7]+
        data[6]*Math.pow(2,8*1)+
        data[5]*Math.pow(2,8*2)+
        data[4]*Math.pow(2,8*3)+
        data[3]*Math.pow(2,8*4)+
        data[2]*Math.pow(2,8*5)+
        (data[1]&15)*Math.pow(2,8*6)+
        Math.pow(2,52);

    return Math.pow(-1,sign)*mantissa*mul;
}

var data = atob("AAAAAABsskAAAAAAAPmxQAAAAAAAKrF");

alert(bytesToDouble(data,0)); // 4716.0
alert(bytesToDouble(data,1)); // 4601.0

This should give you a push in the right direction, though it took me a while to remember how to deal with doubles.

One big caveats to note though:

This relies on the atob to do the base64 decoding, which is not supported everywhere, and aside from that probably isn't a great idea anyway. What you really want to do is unroll the base64 encoded string to an array of numbers (bytes would be the easiest to work with although not the most efficient thing on the planet). The reason is that when atob does its magic, it returns a string, which is far from ideal. Depending on the encoding the code points it maps to (especially for code points between 128 and 255) the resulting .charCodeAt() may not return what you expect.

And there may be some accuracy issues, because after all I am using a double to calculate a double, but I think it might be okay.

Base64 is fairly trivial to work with, so you should be able to figure that part out.

If you did switch to an array (rather than the str string now), then you would obviously drop the .charCodeAt() reference and just get the indices you want directly.

There is a functioning fiddle here

I assume we have used this function in web service (c#) to encode the double array data as string:

//Input: [552.4, 539.8]
//Output: IOz0gCAsscA=

private string ConvertToSerializableString(double[] input)
{
  byte[] data = new byte[input.Length * 4];
  for (int i = 0; i < input.Length; i++)
  {
    int source = (int)(input[i] * 1E6);    
    int dataIndex = i * 4;
    data[dataIndex] = (byte)((source >> 24) & 0xFF);
    data[dataIndex + 1] = (byte)((source >> 16) & 0xFF);
    data[dataIndex + 2] = (byte)((source >> 8) & 0xFF);
    data[dataIndex + 3] = (byte)(source & 0xFF);
  }

  return Convert.ToBase64String(data);          
}

Then we can use the following client script (javascript) to decode it:

var base64EncodedDoubleArrayData = "IOz0gCAsscA=";
var byteData = window.atob(base64EncodedDoubleArrayData);                

var doubleArray = [];
for (var iColumn = 0; iColumn < byteData.length; iColumn = iColumn + 4) 
{
   var item = (byteData.charCodeAt(iColumn) << 24) + (byteData.charCodeAt(iColumn + 1) << 16) + (byteData.charCodeAt(iColumn + 2) << 8) + byteData.charCodeAt(iColumn + 3);   
   var doubleResult = parseFloat(item/1e6);
   doubleArray.push(doubleResult);
}  

//it should return something like doubleArray = [552.4, 539.8]

本文标签: Convert byte array to numbers in JavaScriptStack Overflow