Solved Convert quint16 to float number
-
Hi everybody,
my question is not really Qt specific, but my search through the internet wasn't successful.I get a quint16 number (representing a floating number) from a function and want to convert it to a floating number https://en.wikipedia.org/wiki/Half-precision_floating-point_format
Like:
float quint16ToFloat(quint16 value) { // insert magic stuff return myFloat; }
Can anybody help?
Thanks
[Moved to C++ Gurus ~kshegunov]
-
Hi,
Try something along these lines:float quint16ToFloat(quint16 value) { union { quint16 v; struct { qint8 sign : 1; qint8 exponent: 5; qint16 fraction: 10; } frep; } halfPrecisionFloat; union { float v; struct { qint8 sign : 1; qint8 exponent: 8; qint16 fraction: 23; } frep; } singlePrecisionFloat; halfPrecisionFloat.v = value; singlePrecisionFloat.frep.sign = halfPrecisionFloat.frep.sign; singlePrecisionFloat.frep.exponent = halfPrecisionFloat.frep.exponent; singlePrecisionFloat.frep.fraction = halfPrecisionFloat.frep.fraction; return singlePrecisionFloat.v; }
... or alternatively ...
float quint16ToFloat(quint16 value) { quint32 result = (static_cast<quint32>(value & 0x8000) << 16) | (static_cast<quint32>(value & 0x7FF) << 13); return *reinterpret_cast<float *>(&result); // ... don't ask ... }
Warning:
You should bear in mind, however, that the first snippet is relying on the C++ compiler following the C99 standard, not the C++11 on unions (which is the case in my experience, but still ...!). In the latter reading an uninitialized field from a union is undefined, the former has defined behavior. The second code snippet isn't all roses either, it allows for alignment specific problems (because of the nasty reinterpret at the end).EDIT:
I've corrected an error in the second snippet. The mantissa bits should be aligned to the rightmost possible significant bit as they're inverse powers (i.e. 1/2, 1/4, 1/8 etc).Kind regards.
-
Depending on your platform there might be more options, e.g. compiler extensions.
-
@Wieland
The application will be run on windows, x86 architecture.I found some good papers like http://blog.schmorp.de/data/binary16/fasthalffloatconversion.pdf
I didn't expect that the conversion is such difficult.
The data i will receive are temperatures of a modus tcp register from this module
In my case the temperature range is between +20°C to +500°C.
-
@beecksche said in Convert quint16 to float number:
I found some good papers like http://blog.schmorp.de/data/binary16/fasthalffloatconversion.pdf
Good find. I've forgotten about the special values ... *_* sounds silly for a person bragging about knowing floating point arithmetic inside out ... :)
I didn't expect that the conversion is such difficult.
It's not a native type, that's the reason, you don't have hardware support for half-precision fp numbers.
-
So i have just implemented the formula given here
float quint16ToFloat(const quint16 & value) { int sign = value >> 15 & 1; int exponent = 0; for (int i = 10; i <=14; i++) exponent |= (value >> i & 1) << (i - 10); float mantissa = 0; for (int i = 0; i <= 9; i++) mantissa += (value >> i & 1) * qPow(2.0, -1.0 * (9 - i + 1)); if (exponent >= 1 && exponent <= 30) mantissa +=1; if (exponent == 0 && mantissa == 0) return 0.0; if (exponent == 31 && mantissa == 0) ; //infinity if (exponent == 31 && mantissa != 0) ; // Nan qDebug() << "Sign: " << sign; qDebug() << "Exponent: " << exponent - 15; qDebug() << "Mantissa: " << mantissa; return qPow(-1.0, sign) * qPow(2.0, exponent - 15) * mantissa; } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); quint16 value = 20384; // Operand A = 30.5 = 0 10011 1110100000 = 20384 qDebug() << "quint16: " << value << "float: " << quint16ToFloat(value); return a.exec(); }
Output:
Sign: 0
Exponent: 4
Mantissa: 1.90625
quint16: 20384 float: 30.5Here is a online converter and i get the same results http://oletus.github.io/float16-simulator.js/
It seems to work.
-
@beecksche I'm wondering why they use floating point numbers for that (which are not even standardised!)? Why not use uint16 and represent 1°C as lets say 10?
Then 20,5 would be 205.
I hope they do not develop anything for financial area using floating point numbers :-) -
@jsulm
You're right! I misinterpreted the documentation of the temperature module.
Today i've tested it and get the wrong temperatures.In the module you can set a temperature resolution: 0.01 °C or 0.1 °C. The value i get is a 16 bit value, the 15th bit is the sign and the other 15 bit (0 - 14) represent the temperature depending in the set resolution.
Resolution Data Bits Sign Value Temperature 0.01 2046 0 000011111111110 + 2046 20.46 0.1 204 0 000000011001100 + 204 20.4 0.1 32972 1 000000011001100 - 204 -20.4 So it isn't that difiicult as i thought at the beginning. But now i know to convert a 16 bit float value ;-)
Thanks for help!
-
@jsulm said in Convert quint16 to float number:
I hope they do not develop anything for financial area using floating point numbers :-)
As far as my understanding goes, fixed point arithmetic is still the technique of choice for financial (or rather accounting) applications.
@beecksche said in Convert quint16 to float number:
But now i know to convert a 16 bit float value ;-)
Not that you will ever need it ... ;)
... but I'm glad you found a solution.Kind regards.
-
Since Qt 5.9.0 there's a qfloat16 class to handle half-float values https://wiki.qt.io/New_Features_in_Qt_5.9 and https://doc.qt.io/qt-5/qfloat16.html.
The class is based on the algorithms described in the paper http://blog.schmorp.de/data/binary16/fasthalffloatconversion.pdf