IEEE-754 Floating Point Converter

Hello, I am using Node-RED to convert convert IEEE-754 Floating Point to decimal.
I am using this code to convert the values wich I get the right positive values but I obtain -Infinity for the negative values.

Code:
var buf = Buffer.from(msg.payload);
var sign = buf.readFloatBE() >> 31 === 0 ? 1 : -1 ;
var exponent = (buf.readFloatBE() & 0b01111111100000000000000000000000);
var significand = (buf.readFloatBE() & ~(-1 << 23));
msg.payload = sign * significand * Math.pow(2, exponent);
return msg;

Can you please help me to get the negative values.

That exponent calc doesn't look right, it will give you a huge number if the exponent is non-zero. I would have expected to see it shifted right.
Are you sure you get the right values for +ve numbers? Have you tried with a big +ve?
Where did you get the code?

Yes, I get the right +ve values. I didn't tried with a big +ve values ( The maximum value that I converted it is about 4000).

Where did you get that code? It is not right.

Or if you did not copy some code where is the algorithm you are trying to replicate?

I have tried several code after I changed them to get the value that I had . Can you help me please ?

I am not going to start working out the algorithm to do the conversion. If you google and find the algorithm to use (which presumably you have already in order to get nearly there) then I can help you code it in javascript.


I found this code but I didn't get the right Values

function Bytes2Float32(bytes) {
    var sign = (bytes & 0x80000000) ? -1 : 1;
    var exponent = ((bytes >> 23) & 0xFF) - 127;
    var significand = (bytes & ~(-1 << 23));

    if (exponent == 128) 
        return sign * ((significand) ? Number.NaN : Number.POSITIVE_INFINITY);

    if (exponent == -127) {
        if (significand == 0) return sign * 0.0;
        exponent = -126;
        significand /= (1 << 22);
    } else significand = (significand | (1 << 23)) / (1 << 23);

    return sign * significand * Math.pow(2, exponent);
}

That looks more likely to be correct. Have you got some sample values and what they should convert to?

That function works for me with examples from https://en.wikipedia.org/wiki/Single-precision_floating-point_format

[{"id":"f64c029.2c5838","type":"function","z":"2ae8b25a.bffaa6","name":"Bytes to float","func":"let bytes = Number(msg.payload);\nmsg.payload = Bytes2Float32(bytes)\nreturn msg;\n\nfunction Bytes2Float32(bytes) {\n    var sign = (bytes & 0x80000000) ? -1 : 1;\n    var exponent = ((bytes >> 23) & 0xFF) - 127;\n    var significand = (bytes & ~(-1 << 23));\n\n    if (exponent == 128) \n        return sign * ((significand) ? Number.NaN : Number.POSITIVE_INFINITY);\n\n    if (exponent == -127) {\n        if (significand === 0) return sign * 0.0;\n        exponent = -126;\n        significand /= (1 << 22);\n    } else significand = (significand | (1 << 23)) / (1 << 23);\n\n    return sign * significand * Math.pow(2, exponent);\n}","outputs":1,"noerr":0,"x":310,"y":612,"wires":[["6e888b6a.40c874"]]},{"id":"6e888b6a.40c874","type":"debug","z":"2ae8b25a.bffaa6","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":502,"y":612,"wires":[]},{"id":"2dc3b0d4.06517","type":"inject","z":"2ae8b25a.bffaa6","name":"1","topic":"","payload":"0x3f800000","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":89,"y":614,"wires":[["f64c029.2c5838"]]},{"id":"43e54f8e.0cf598","type":"inject","z":"2ae8b25a.bffaa6","name":"-2","topic":"","payload":"0xc0000000","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":84,"y":650,"wires":[["f64c029.2c5838"]]},{"id":"a8fc7865.b2a438","type":"inject","z":"2ae8b25a.bffaa6","name":"Pi","topic":"","payload":"0x40490fdb","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":82,"y":684,"wires":[["f64c029.2c5838"]]}]

Thank you very much @Colin.
But I have just one question to ask. befor the function node I have a node which I obtain a buffer like this [67,76,0,0]. I have to change Number to buffer? like this :
let bytes = buffer.from(msg.payload);
msg.payload = Bytes2Float32(bytes)
return msg;
I changed it but I get always 0.

It is important to be careful in your choice of words. You say you have a buffer like [67,67,0,0] but then say you want to use buffer.from on it. If it is already a buffer then why do buffer.from? I suspect you mean that it is an array. If so then there is no need to convert it to a buffer. If the array is in msg.payload you can do

let bytes = (((((msg.payload[0] << 8) + msg.payload[1]) << 8) + msg.payload[2]) << 8) + msg.payload[3]
msg.payload = Bytes2Float32(bytes)
return msg;
1 Like

The wikipedia post has an error. Not in the conversion but 3.1415927410 is not pi!

[Edit] No it isn't, that is as close as you can get in single precision float.

As this has come up before I have added a flow to flows library with the function to do this conversion.

https://flows.nodered.org/flow/359ead34237b7ab6ec0465ee85a34b62

2 Likes

Thank you very much @Colin.

Need help. How to modify this function to convert from double (binary64) to decimal.
I try this, but it's not work


let intValue;
if (typeof msg.payload === "number") {
    intValue = msg.payload;
} else if (typeof msg.payload === "string") {
    intValue = Number(msg.payload);
} else if (msg.payload.length == 4) {
    // four byte array or buffer
    intValue = (((((msg.payload[0] << 16) + msg.payload[1]) << 16) + msg.payload[2]) << 16) + msg.payload[3];
} else {
    node.warn("Unrecognised payload type or length");
}

msg.payload = Int2Float32(intValue);
return msg;

function Int2Float32(bytes) {
    var sign = (bytes & 0x80000000) ? -1 : 1;
    var exponent = ((bytes >> 52) & 0xFF) - 1023;
    var significand = (bytes & ~(-1 << 52));

    if (exponent == 1) 
        return sign * ((significand) ? Number.NaN : Number.POSITIVE_INFINITY);

    if (exponent == -1023) {
        if (significand === 0) return sign * 0.0;
        exponent = -1022;
        significand /= (1 << 51);
    } else significand = (significand | (1 << 52)) / (1 << 52);

    return sign * significand * Math.pow(2, exponent);
}

Send the incoming message to a debug node and show us what you see, otherwise we don't know what you are starting with

msg.payload : Object
object
data: array[4]
0: 16550
1: 25493
2: 13159
3: 782
buffer: buffer[8][raw](http://127.0.0.1:1880/#)
0: 0x40
1: 0xa6
2: 0x63
3: 0x95
4: 0x33
5: 0x67
6: 0x3
7: 0xe

It's mast be 2.87 kWh

Device which i read registers is pac3200, offset 801, 4 regesters, double format, Overflow 1.0e+12 .

After converting, I have
msg.payload : number
2.8824866727954215e-292

This converter (https://www.binaryconvert.com/result_double.html?hexadecimal=40A663953367300E) tell me, decimal value = 2.86579140779935460159322246909E3

Please post a flow including an inject node and your function showing it not working.
Note that you have the wrong link (it should end 030E not 300E) but that does not make much difference.

[{"id":"f2043821.10b2a8","type":"function","z":"7b2adc08.02a074","name":"IEEE-754 to float","func":"/* Converts from an number, string, buffer or array representing an IEEE-754 value\n * to a javascript float.\n * The following may be given in msg.payload:\n * A string representing a number, which may be hex or binary\n * examples, \"1735\" \"0x02045789\" 0b01000000010010010000111111011011\n * An integer value\n * A four element array or buffer of 8 bit values, most significant byte first.\n*/ \n// first make a number from the given payload if necessary\nlet intValue;\nif (typeof msg.payload === \"number\") {\n intValue = msg.payload;\n} else if (typeof msg.payload === \"string\") {\n intValue = Number(msg.payload);\n} else if (msg.payload.length == 4) {\n // four byte array or buffer\n intValue = (((((msg.payload[0] << 16) + msg.payload[1]) << 16) + msg.payload[2]) << 16) + msg.payload[3];\n} else {\n node.warn(\"Unrecognised payload type or length\");\n}\n\nmsg.payload = Int2Float32(intValue);\nreturn msg;\n\nfunction Int2Float32(bytes) {\n var sign = (bytes & 0x80000000) ? -1 : 1;\n var exponent = ((bytes >> 52) & 0xFF) - 1023;\n var significand = (bytes & ~(-1 << 52));\n\n if (exponent == 1) \n return sign * ((significand) ? Number.NaN : Number.POSITIVE_INFINITY);\n\n if (exponent == -1023) {\n if (significand === 0) return sign * 0.0;\n exponent = -1022;\n significand /= (1 << 51);\n } else significand = (significand | (1 << 52)) / (1 << 52);\n\n return sign * significand * Math.pow(2, exponent);\n}","outputs":1,"noerr":0,"x":390,"y":80,"wires":[["583f7267.d123bc"]]},{"id":"583f7267.d123bc","type":"debug","z":"7b2adc08.02a074","name":"Value","active":true,"tosidebar":true,"console":true,"tostatus":false,"complete":"payload","x":600,"y":80,"wires":[]},{"id":"485407f3.a2f768","type":"inject","z":"7b2adc08.02a074","name":"fromeRegesters","topic":"","payload":"[16550,25493,13159,782]","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":80,"wires":[["f2043821.10b2a8"]]}]

Thanks. You are right about 030E.