2015-06-23 4 views
0

Приведенный ниже код просто преобразует 32-битное целое из объекта, передаваемого функции, 32-разрядное целое представляет собой плавающее число. Я проверил с помощью онлайн-калькулятора, что я получаю знак, экспоненту и мантессу правильным способом, но странно, что я получаю ответ неправильно.IEEE754 с плавающей запятой C#

Может кто-нибудь, пожалуйста, проверьте, математически ли я (или, может быть, программно), что-то неправильно это сделал !?

С уважением

public double FromFloatSafe(object f) 
    { 
     uint fb = Convert.ToUInt32(f); 


     uint sign, exponent = 0, mantessa = 0; 
     uint bias = 127; 

     sign = (fb >> 31) & 1; 
     exponent = (fb >> 23) & 0xFF; 
     mantessa = (fb & 0x7FFFFF); 
     double fSign = Math.Pow((-1), sign); 
     double fMantessa = 1 + (1/mantessa); 
     double fExponent = Math.Pow(2, (exponent -bias)); 
     double ret = fSign * fMantessa * fExponent; 
     return ret; 
    } 
+3

'BitConverter.GetBytes (FB)' и затем 'BitConverter.ToSingle()'? –

+1

Использование 'Math.Pow' для fSign немного раздуто :-)' sign == 0? 1: -1'. И это мантисса, а не мантесса. – xanatos

+0

Почему вы передаете число с плавающей запятой в виде целого числа? Что вы на самом деле пытаетесь сделать? C# может обрабатывать отливки просто отлично, почему вы используете неправильные типы данных? – Luaan

ответ

2

Нечто подобное:

uint fb = Convert.ToUInt32(f); 

    return BitConverter.ToSingle(BitConverter.GetBytes((int) fb), 0); 
+0

Спасибо, что это правильный ответ, который я искал! – Combinu

0

Это обрабатывает даже denormal номера:

public static float FromFloatSafe(object f) 
{ 
    uint fb = Convert.ToUInt32(f); 

    int sign = (int)((fb >> 31) & 1); 
    int exponent = (int)((fb >> 23) & 0xFF); 
    int mantissa = (int)(fb & 0x7FFFFF); 

    float fMantissa; 
    float fSign = sign == 0 ? 1.0f : -1.0f; 

    if (exponent != 0) 
    { 
     exponent -= 127; 
     fMantissa = 1.0f + (mantissa/(float)0x800000); 
    } 
    else 
    { 
     if (mantissa != 0) 
     { 
      // denormal 
      exponent -= 126; 
      fMantissa = 1.0f/(float)0x800000; 
     } 
     else 
     { 
      // +0 and -0 cases 
      fMantissa = 0; 
     } 
    } 

    float fExponent = (float)Math.Pow(2.0, exponent); 
    float ret = fSign * fMantissa * fExponent; 
    return ret; 
} 

обратите внимание, что я думаю, что есть что-то подозрительное, но вы попросил, я написал его ... Я чувствую, что это XY problem.

Ах ... и обратите внимание, что в то время как академически, что я писал очень интересно, я обычно делаю это так:

[StructLayout(LayoutKind.Explicit)] 
public struct UInt32ToFloat 
{ 
    [FieldOffset(0)] 
    public uint UInt32; 

    [FieldOffset(0)] 
    public float Single; 
} 

затем

float f = new UInt32ToFloat { UInt32 = Convert.ToUInt32(f) }.Single; 
+0

Примечание: 'struct' /' [FieldOffset] 'является очень хорошим подходом (без вычислений) - но работает только для двух типов с одинаковой длиной бит (в данном случае 32 бит для uint/float) – joe

+0

@joe Вы даже можете использовать он разбивает верхний/нижний 'Int32'' Int64', если вы хотите ... (или 4x'Int16' 'Int64') – xanatos

+0

Это правда, но я имел в виду, что преобразование' Int16' в 'double' не будет работать таким образом из-за знака. – joe

Смежные вопросы