У меня есть некоторая ошибка точности во время преобразования из 16-битного формата с плавающей запятой половинной точности в десятичный. Он может точно преобразовывать одни числа и в то же время неточно для других.
Первоначально код был разработан для 32-битного преобразования одинарной точности с плавающей запятой в десятичное число. Таким образом, я попытался отредактировать его, чтобы он соответствовал 16-битному формату с плавающей запятой половинной точности. В результате полученное окончательное значение оказалось вдвое меньше ожидаемого.
Например. Ожидаемое значение будет 1800
, результатом будет 900
.
Таким образом, я решил добавить * 2
к финальной операции. Я не уверен, как исправить текущую ошибку точности, которая у меня есть, и почему результат также вдвое меньше ожидаемого значения.
Ниже приведен код, который я отредактировал с соответствующими результатами.
#include <stdio.h>
//#include <bits/stdc++.h>
#include <string>
#include <iostream>
#include <sstream>
#include <math.h>
#include <limits.h>
#include <bitset>
using namespace std;
// Convert the 16-bit binary encoding into hexadecimal
int Binary2Hex( std::string Binary )
{
std::bitset<16> set(Binary);
int hex = set.to_ulong();
return hex;
}
// Convert the 16-bit binary into the decimal
float GetFloat16( std::string Binary )
{
int HexNumber = Binary2Hex( Binary );
printf("Test: %d\n", HexNumber);
bool negative = !!(HexNumber & 0x8000);
int exponent = (HexNumber & 0xf800) >> 10;
int sign = negative ? -1 : 1;
// Subtract 15 from the exponent
exponent -= 15;
// Convert the mantissa into decimal using the
// last 10 bits
int power = -1;
float total = 0.0;
for ( int i = 0; i < 10; i++ )
{
int c = Binary[ i + 6 ] - '0';
total += (float) c * (float) pow( 2.0, power );
power--;
}
total += 1.0;
float value = sign * (float) pow( 2.0, exponent ) * total * 2;
}
16-битное значение с плавающей запятой, которое я использую, будет: 0101010100010011
Ожидаемый результат: 81.2
Фактический результат: 81.1875
18.2
быть точно представлено в 16-битном формате с плавающей запятой? Нет ошибок округления из-за всей математики, которую вы делаете (и помните, что ошибки округления складываются)? - person Some programmer dude   schedule 05.08.20190101010100010011
, и оно преобразуется в 81,2 - person Kai   schedule 05.08.2019GetFloat16
возвращает значение, потому что она не содержит оператораreturn
. - person Eric Postpischil   schedule 05.08.20190x7c00
, а не0xf800
. - person Eric Postpischil   schedule 05.08.2019pow
для точного возведения в степень, потому что некоторые реализации заведомо плохи тем, что не могут вернуть правильные результаты, когда математический результат точно представим. Он также может плохо работать. Обычно необходимые арифметические действия для такого рода работы можно выполнить с помощью простого умножения и деления. Если это невозможно,ldexp
является лучшей альтернативойpow
. На самом деле цикл и использованиеpow
совершенно не нужны. Цикл можно заменить наtotal = (HexNumber & 0x3ff) / 1024.;
. - person Eric Postpischil   schedule 05.08.2019*
изfloat value = … * total * 2;
. Я предполагаю, что вы добавили это, чтобы сделать результат приблизительно правильным, но это было необходимо только из-за правильной маски экспоненты, упомянутой выше. - person Eric Postpischil   schedule 05.08.201981.2
от0101010100010011
? Он имеет знак0
, показатель степени10101
, который равен 21 смещенному, 6 натуральному, и мантиссу 1,0100010011, что равно 1,2685546875, поэтому представленное число равно +1 • 2^6 • 1,2685546875 = 81,1875. - person Eric Postpischil   schedule 05.08.2019* 2
, чтобы получить лучший результат, так как я не был уверен, какие еще поля мне нужно отредактировать. Я ожидал81.2
от0101010100010011
, так как онлайн-калькулятор предоставил этот ответ. - person Kai   schedule 06.08.2019