QbyteArray浮动

时间:2016-04-26 08:31:18

标签: c++ qt floating-point qbytearray

我有一个将QByteArray转换为float的函数,它的工作原理完全正常,除非我将其提供为0,而是5.87747e-39而不是0.0

float QByteArrayToFloat(QByteArray f){
    bool ok;
    int sign = 1;

    f = f.toHex(); // Convert to Hex

    qDebug() << "QByteArrayToFloat: QByteArray hex = " << f;

    f = QByteArray::number(f.toLongLong(&ok, 16), 2);    // Convert hex to binary

    if(f.length() == 32) {
        if(f.at(0) == '1') sign =-1;     // If bit 0 is 1 number is negative
        f.remove(0,1);                   // Remove sign bit
    }

    QByteArray fraction = f.right(23);  // Get the fractional part
    double mantissa = 0;
    for(int i = 0; i < fraction.length(); i++){  // Iterate through the array to claculate the fraction as a decimal.
        if(fraction.at(i) == '1')
            mantissa += 1.0 / (pow(2, i+1));
    }

    int exponent = f.left(f.length() - 23).toLongLong(&ok, 2) - 127;     // Calculate the exponent

    qDebug() << "QByteArrayToFloat: float number = "<< QString::number(sign * pow(2, exponent) * (mantissa + 1.0),'f', 5);

    return (sign * pow(2, exponent) * (mantissa + 1.0));
}

检查零的QByteArrayisEmpty()无效)中没有有用的功能。我可以(toHex()之后)if(f.indexOf("00000000") == -1) return 0.0;if(exponent = -127 && mantissa == 0) return 0.0;,但是有更优雅的解决方案吗?

另外,有趣的是QString::number(sign * pow(2, exponent) * (mantissa + 1.0),'f', 5);工作正常并打印"0.00000"。但是,只要我将toFloat(&ok);转换回浮动状态,就会发生同样的事情。

2 个答案:

答案 0 :(得分:2)

我引用了document

  

非规范化数字

     

如果你有一个指数字段都是零位,那就是这个   称为非规范化数字。指数字段等于零,   你会认为真正的指数是-127,所以这个数字   将采用如上所述的1.MANTISSA * 2-127的形式,但它   才不是。相反,它是0.MANTISSA * 2-126。注意指数   不再是指数字段的值减去127.这很简单   -126。另请注意,我们不再为尾数包含隐含的一位。

     

     

您可以将零视为另一个非规范化数字。零是   由指数零和零尾数表示。从我们的   理解非规范化数字,这转化为0 * 2-126 =   该符号位可以是正(0)或负(1),可以是正零或负零。这不是很重要   在数学上有道理,但这是允许的。

将代码纠正为零以后:

int exponent = - 126;
// and
return (sign * pow(2, exponent) * (mantissa + 0.0));

我得到答案 0.0

答案 1 :(得分:0)

我发现使用位移和QByteArray进行floatreinterpret_cast转换的更好解决方案。它还处理零值。

float QByteArrayToFloat(QByteArray arr)
{
    static_assert(std::numeric_limits<float>::is_iec559, "Only supports IEC 559 (IEEE 754) float");

    quint32 temp = ((char)arr[0] << 24)|((char)arr[1] << 16)|((char)arr[2] << 8)|(char)arr[3]; // Big endian
    float* out = reinterpret_cast<float*>(&temp);

    return *out;
}