Как получить биты «двойник» как «длинный» - PullRequest
10 голосов
/ 18 декабря 2010

Я хотел бы манипулировать побитовым представлением чисел с плавающей точкой в ​​C #. BinaryWriter и BinaryReader делают это следующим образом:

public virtual unsafe void Write(double value)
{
    ulong num = *((ulong*) &value);
    ...
}
public virtual unsafe double ReadDouble()
{
    ...
    ulong num3 = ...;
    return *((double*) &num3);
}

Есть ли способ сделать это без небезопасного кода и без накладных расходов по фактическому использованию BinaryWriter и BinaryReader?

Ответы [ 3 ]

8 голосов
/ 18 декабря 2010

Другой способ - использовать пользовательскую структуру с явным макетом, который определяет как long, так и double со смещением 0. Это эквивалентно union в C.

Примерно так:

using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Explicit)]
struct DoubleLongUnion
{
    [FieldOffset(0)] 
    public long Long;
    [FieldOffset(0)] 
    public double Double;
}

Тогда используйте это:

var union = new DoubleLongUnion();
union.Double = 1.234d;
var longBytes = union.Long;

Это позволит избежать любого небезопасного кода и должно работать довольно быстро, так как вы выполняете преобразование в стеке.

Я не пробовал / не компилировал это, но я считаю, что это должно работать:)

РЕДАКТИРОВАТЬ

Я только что попробовал это, и это работает. Значение longBytes выше составляет 4608236261112822104.

Некоторые другие значения:

0d              -> 0L
double.NaN      -> -2251799813685248L
double.MinValue -> -4503599627370497L
double.MaxValue -> 9218868437227405311L

Вот метод, который делает то, что вы хотите:

public static long DoubleToLong(double d)
{
    return new DoubleLongUnion { Double = d }.Long;
}
6 голосов
/ 18 декабря 2010

Вы можете использовать byte[] BitConverter.GetBytes(double) и long BitConverter.ToInt64(byte[],int) (передавая 0 в качестве начального индекса), но внутренне IIRC использует небезопасный код, плюс накладные расходы массива.Выбери свой яд ...

4 голосов
/ 18 декабря 2010

Вы пытаетесь вообще избежать небезопасного кода или просто хотите использовать альтернативу этим конкретным методам на BinaryReader и BinaryWriter?

Вы можете использовать BitConverter.DoubleToInt64Bitsи BitConverter.Int64BitsToDouble, предназначенные для выполнения именно того, что вам нужно, хотя я думаю, что они используют такое же небезопасное преобразование за кадром, что и методы BinaryReader / BinaryWriter.

...