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]


  • Qt Champions 2016

    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.


  • Moderators

    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.


  • Qt Champions 2016

    @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.



  • @kshegunov

    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.5

    Here is a online converter and i get the same results http://oletus.github.io/float16-simulator.js/

    It seems to work.


  • Moderators

    @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!


  • Qt Champions 2016

    @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


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.