Формат single IBM float point преобразование в Csharp Single(float) формат - C#
Формулировка задачи:
Возникла проблема с чтением данных в формате IBM float point. Пытался найти какой-либо простой метод преобразования во внутренний форма CSharp, не вышло. Начал побайтно разбирать его, прочитал википедию. Там все просто:
SEF : S EEEEEEE FFFFFFFF FFFFFFFF FFFFFFFF
bits : 1 2 8 9 32
bytes : byte1 byte2 byte3 byte4
Первый бит - знак, потом экспонента(2-8 биты) и некий "Fractoin"- если, кто объяснит, как он на русском называется буду благодарен. Написал код:
1.Если у кого были подобные трудности, может поделитись опытом и объяснити странные повороты туда-сюда.
2. Может у кого-нибудь есть идеи оптимизации, слошком много циклов на мой взгляд.
public static float IBMEncoding(byte[] bInputBytes)
{
//Method of conversation from IBM Float point to Csharp single format.
float fOutput = 0; //результат
int A = 16; // Постоянный для IBM float множетиль
int B = 64; // Константа степени.
double dFraction = 0; // тот самый fraction= 1/2+1/4+...+(1/2)^n;
int iExp = 0; // экспонентаю
int iSign; //знак
int[] b = new int[32];
#region Bit2Int // проблемы начались с самого начала данные в BigEndian формате Csharp упорно хотел LittleEndian
// пришлось разворачивать. К тому же использование массива int мне показалось более удобным в
// сравнении с использоавнием битных шифтов и прочих радостей вычлинения битов из байта.
for (int j = 0; j < bInputBytes.Length; j++)
{
for (int i = 0; i < 8; i++)
{
b[31 - (j * 8 + i)] = bInputBytes[j] >> i & 0x1; ;
;
};
};
#endregion
iSign = Convert.ToInt32(Math.Pow(-1 , b[0])); // Получил знак собстевнно из первого бита.
for (int i = 1; i < 8; i++) //Получаю значение экспоненты
{
iExp = Convert.ToInt32(iExp + Math.Pow(2, i-1) * b[8-i]); // Это место мне совершенно не понятно, может кто уточнит
// Я использую обратный порядок для получения
// экспоненты т.е. самые большие значения у меня слева.
// Это единственный способ получения нужного результат
// Если кто понимает в этом может объяснить как так?
};
for (int i = 8; i < 32; i++) // Fraction
{
dFraction = dFraction + Math.Pow(0.5, i-8)*b[i]; //Получаю Fraction его уже не разворачиваю
};
fOutput = Convert.ToSingle( iSign*dFraction*Math.Pow(A,(iExp-B))); // Все вставляю в окончательную формулу
// и получаю искомое значение (проверено сторонним софтом)
return fOutput;
}Решение задачи: «Формат single IBM float point преобразование в Csharp Single(float) формат»
textual
Листинг программы
float ibm = -157.1817f; var raw = *(int*)&ibm; var sign = raw >> 31 & 0x01; var exponent = raw >> 24 & 0x7f; var mantissa = (raw & 0x00ffffff) / (float)(1 << 24); var ieeeFloat = (1 - 2 * sign) * mantissa * (float)Math.Pow(16, exponent - 64);