如何将“双”的位称为“长”

时间:2010-12-17 23:19:38

标签: .net floating-point bit-manipulation

我想在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 个答案:

答案 0 :(得分:8)

另一种方法是使用具有显式布局的自定义结构,该结构在偏移0处定义longdouble。这相当于C中的union

这样的事情:

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;
}

答案 1 :(得分:6)

你可以使用byte[] BitConverter.GetBytes(double)long BitConverter.ToInt64(byte[],int)(传递0作为起始索引),但内部 IIRC这些使用不安全的代码,加上数组的开销。选择你的毒药......

答案 2 :(得分:4)

您是在尝试完全避免使用不安全的代码,还是只想在BinaryReaderBinaryWriter上替换这些特定方法?

您可以使用BitConverter.DoubleToInt64BitsBitConverter.Int64BitsToDouble,它们可以完全满足您的需求,但我认为他们使用与BinaryReader /一样的幕后不安全转换BinaryWriter方法。