Привести float к int без ЛЮБЫХ преобразований? - PullRequest
9 голосов
/ 07 ноября 2011

Я записываю различные типы в поток байтов путем ручного приведения и сдвига значений.Я обнаружил, что это более чем в три раза быстрее, чем при использовании BitConverter или BinaryWriter.

Моя проблема с плавающей точкой.Мне нужно привести их к целым числам, чтобы выполнить над ними операции сдвига, но любое приведение к int вызовет неявное преобразование с усечением и т. Д. Я хочу, чтобы точное двоичное представление оставалось неизменным.Возможно ли это?

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

byte[] bytes = new byte[4];
float myFloat = 32.2;

//following won't compile as can't shift floats.
bytes [0] = (byte)myFloat;
bytes [1] = (byte)(myFloat >> 8);
bytes [2] = (byte)(myFloat >> 16);
bytes [3] = (byte)(myFloat >> 24);

Ответы [ 3 ]

15 голосов
/ 29 мая 2013

Следующее не требует небезопасного кода и доказано, что оно работает (я использовал его годами в различных версиях .NET):

[StructLayout(LayoutKind.Explicit)]
public struct FloatAndUIntUnion
{
    [FieldOffset(0)]
    public uint  UInt32Bits;
    [FieldOffset(0)]
    public float FloatValue;
}


FloatAndUIntUnion f2i = default(FloatAndUIntUnion);
f2i.FloatValue = aFloat;    // write as float
uint i = f2i.UInt32Bits;    // read back as int

Обратите внимание, что направление float → int может быть проще:

int i = aFloat.GetHashCode();

Однако, это гораздо более неясно, потому что не задокументировано (согласно MSDN ), хотя подтверждено этим постом .(То есть в 2006 году поведение было таким же, как и в 2013 году, и я не вижу причин менять его в будущем - но это может произойти, и я не уверен, будет ли это рассматриваться как несовместимое с обратным изменением или нет.)

6 голосов
/ 07 ноября 2011

Можете ли вы использовать double вместо float?

double doubleValue = 32.2;
long setofBits = BitConverter.DoubleToInt64Bits(doubleValue);

РЕДАКТИРОВАТЬ: Ответ на комментарий

Я полагаю, что при использовании BitConverter нет накладных расходов, мы можем увидеть, что его реализация довольно проста:

public static unsafe long DoubleToInt64Bits(double value)
{
    return *(((long*) &value));
}
5 голосов
/ 07 ноября 2011
float myFloat = 0.124112f;
float[] floats = new[] { myFloat };
byte[] bytes = new byte[4];
Buffer.BlockCopy(floats, 0, bytes, 0, 4);

РЕДАКТИРОВАТЬ: по сравнению с DoubleToInt64Bits это медленнее, хотя и в 4 раза больше на моей машине, что имеет смысл, учитывая его характер массива и неизбежные издержки по сравнению с крайней простотой реализации DoubleToInt64Bits.

...