QbyteArray要浮动

QbyteArray to float

我有一个将 QByteArray 转换为 float 的函数,它工作得很好,除非我给它输入零,我得到 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));
}

QByteArray 中没有有用的函数(isEmpty() 不起作用)检查零。我可以(在 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);,同样的事情就会发生。

我引用这个document:

Denormalized Numbers

If you have an exponent field that's all zero bits, this is what's called a denormalized number. With the exponent field equal to zero, you would think that the real exponent would be -127, so this number would take the form of 1.MANTISSA * 2-127 as described above, but it does not. Instead, it is 0.MANTISSA * 2-126. Notice that the exponent is no longer the value of the exponent field minus 127. It is simply -126. Also notice that we no longer include an implied one bit for the mantissa.

Zero

You can think of zero as simply another denormalized number. Zero is represented by an exponent of zero and a mantissa of zero. From our understanding of denormalized numbers, this translates into 0*2-126 = 0. This sign bit can be either positive (0) or negative (1), leading to either a positive or negative zero. This doesn't make very much sense mathematically, but it is allowed.

将零大小写的代码更正为:

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

我得到答案0.0

我发现有一个更好的解决方案,可以使用移位和 reinterpret_castQByteArray 转换为 float。它还处理零值。

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;
}