我有一个将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));
}
检查零的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);
转换回浮动状态,就会发生同样的事情。
答案 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
进行float
到reinterpret_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;
}