开发者

Convert 32bit unsigned "Real" data type (splitted into two 16 bit signed words) to javascript

i've got a 32 bit unsigned "Real" value splitted into two 16 Bit signed "Word" (0-65535) values. H开发者_StackOverflow中文版ow do I convert them to a javascript number?

Example: Value1: 18584 Value2: 18081 The Real value is: 20644.3

I'm searching for a function like back2Real(18584, 18081) which returns 20644.3. The values come from a modbus application (NodeJS / modbus_stack). The SPS/modbus server sends a "Real" value splitted into two Word-registers.

Regards, root66


You can use the new(ish) typed array functionality to simplify this.

function uint16ToFloat32(low, high) {
  var buffer = new ArrayBuffer(4);
  var intView = new Uint16Array(buffer);
  var floatView = new Float32Array(buffer);

  intView[0] = low;
  intView[1] = high;
  return floatView[0];
}

function float32ToUint16(value) {
  var buffer = new ArrayBuffer(4);
  var intView = new Uint16Array(buffer);
  var floatView = new Float32Array(buffer);

  floatView[0] = value;
  return [intView[0], intView[1]];
}

console.log("Converted ints to", uint16ToFloat32(18584, 18081));
console.log("Converted float to", float32ToUint16(20644.297));

Here's a transcript:

$ node floatsplit.js
Converted ints to 20644.296875
Converted float to [ 18584, 18081 ]
$


Use this function to convert to JavaScript numbers. Since JavaScript uses double precision rather than single precision numbers, some rounding may occur.

function back2Real(low, high){
  var fpnum=low|(high<<16)
  var negative=(fpnum>>31)&1;
  var exponent=(fpnum>>23)&0xFF
  var mantissa=(fpnum&0x7FFFFF)
  if(exponent==255){
   if(mantissa!=0)return Number.NaN;
   return (negative) ? Number.NEGATIVE_INFINITY :
         Number.POSITIVE_INFINITY;
  }
  if(exponent==0)exponent++;
  else mantissa|=0x800000;
  exponent-=127
  var ret=(mantissa*1.0/0x800000)*Math.pow(2,exponent)
  if(negative)ret=-ret;
  return ret;
}

The following function converts JavaScript numbers into 32-bit IEEE floating point numbers, split into the low and high word:

function real2Back(value){
  if(isNaN(value))return [0,0xFFC0]
  if(value==Number.POSITIVE_INFINITY || value>=3.402824e38)
    return [0,0x7F80]
  if(value==Number.NEGATIVE_INFINITY || value<=-3.402824e38)
    return [0,0xFF80]
  var negative=(value<0)
  var p,x,mantissa
  value=Math.abs(value)
  if(value==2.0)return [0,0x4000]
  else if(value>2.0){
   // positive exponent
   for(var i=128;i<255;i++){
     p=Math.pow(2,i+1-127)
     if(value<p){
      x=Math.pow(2,i-127)
      mantissa=Math.round((value*1.0/x)*8388608)
      mantissa&=0x7FFFFF
      value=mantissa|(i<<23)
      if(negative)value|=(1<<31)
      return [value&0xFFFF,(value>>16)&0xFFFF]
     }
   }
   // return infinity
   return negative ? [0,0xFF80] : [0,0x7F80]
  } else {
   for(var i=127;i>0;i--){
   // negative exponent
     p=Math.pow(2,i-127)
     if(value>p){
      x=p
      mantissa=Math.round(value*8388608.0/x)
      mantissa&=0x7FFFFF
      value=mantissa|(i<<23)
      if(negative)value|=(1<<31)
      return [value&0xFFFF,(value>>16)&0xFFFF]
     }
   }
   // subnormal
   x=Math.pow(2,i-126)
   mantissa=Math.round((value*8388608.0/x))
   if(mantissa>0x7FFFFF)mantissa=0x800000
   value=mantissa
   if(negative)value|=(1<<31)
   return [value&0xFFFF,(value>>16)&0xFFFF]   
  }
}

I hope this helps. The code is in the public domain.


Buffers normally arrays. Slightly changed first function to accept array, not low and high. It's important to say it's valid for Big Endian format without swap.

function uint16ToFloat32(uint16array) {
    var buffer = new ArrayBuffer(4);
    var intView = new Uint16Array(buffer);
    var floatView = new Float32Array(buffer);

    intView[0] = uint16array[0];
    intView[1] = uint16array[1];
    return floatView[0];
  }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜