将System.Double表示为可排序字符串的最佳方法是什么?

Nat*_*ley 3 .net c# sorting double

在所有基础类型都是字符串的数据格式中,必须将数字类型转换为标准化字符串格式,可以按字母顺序进行比较.例如,a short的值27可以表示为00027没有负数.

表示double字符串的最佳方法是什么?在我的情况下,我可以忽略否定,但我很好奇你在任何一种情况下如何代表双重.

UPDATE

基于Jon Skeet的建议,我现在正在使用它,虽然我不是100%确定它能正常工作:

static readonly string UlongFormatString = new string('0', ulong.MaxValue.ToString().Length);

public static string ToSortableString(this double n)
{
    return BitConverter.ToUInt64(BitConverter.GetBytes(BitConverter.DoubleToInt64Bits(n)), 0).ToString(UlongFormatString);
}

public static double DoubleFromSortableString(this string n)
{
    return BitConverter.Int64BitsToDouble(BitConverter.ToInt64(BitConverter.GetBytes(ulong.Parse(n)), 0));
}
Run Code Online (Sandbox Code Playgroud)

更新2

我已经证实了Jon怀疑 - 使用这种方法的负面效果不起作用.以下是一些示例代码:

void Main()
{
    var a = double.MaxValue;
    var b = double.MaxValue/2;
    var c = 0d;
    var d = double.MinValue/2;
    var e = double.MinValue;
    Console.WriteLine(a.ToSortableString());
    Console.WriteLine(b.ToSortableString());
    Console.WriteLine(c.ToSortableString());
    Console.WriteLine(d.ToSortableString());
    Console.WriteLine(e.ToSortableString());
}

static class Test
{
    static readonly string UlongFormatString = new string('0', ulong.MaxValue.ToString().Length);
    public static string ToSortableString(this double n)
    {
        return BitConverter.ToUInt64(BitConverter.GetBytes(BitConverter.DoubleToInt64Bits(n)), 0).ToString(UlongFormatString);
    }
}
Run Code Online (Sandbox Code Playgroud)

其中产生以下输出:

09218868437227405311
09214364837600034815
00000000000000000000
18437736874454810623
18442240474082181119
Run Code Online (Sandbox Code Playgroud)

显然没有按预期排序.

更新3

以下接受的答案是正确的答案.多谢你们!

Jon*_*eet 5

考虑到巨大的范围(double.MaxValue1.7976931348623157E + 308),填充对双打来说可能相当尴尬.

字符串表示是否仍然必须是人类可读的,或者只是可逆的?

这给出了一个可逆的转换,导致一个相当短的字符串表示,保留了字典顺序 - 但它完全没有明显的double价值来自字符串.

编辑:不要BitConverter.DoubleToInt64Bits单独使用.这颠倒了负值的排序.

我敢肯定,你可以进行使用这个转换DoubleToInt64Bits,然后一些位变换,但不幸的是,我不能让它开始工作,现在和我有三个孩子谁是不顾一切地去公园......


为了使一切正确排序,负数需要以补码格式而不是符号幅度存储(否则负数和正数按相反的顺序排序),并且需要翻转符号位(使负排序小于阳性).这段代码可以解决这个问题:

static ulong EncodeDouble(double d)
{
    long ieee = System.BitConverter.DoubleToInt64Bits(d);
    ulong widezero = 0;
    return ((ieee < 0)? widezero: ((~widezero) >> 1)) ^ (ulong)~ieee;
}

static double DecodeDouble(ulong lex)
{
    ulong widezero = 0;
    long ieee = (long)(((0 <= (long)lex)? widezero: ((~widezero) >> 1)) ^ ~lex);
    return System.BitConverter.Int64BitsToDouble(ieee);
}
Run Code Online (Sandbox Code Playgroud)

演示在这里:http://ideone.com/JPNPY

以下是来自字符串的完整解决方案:

static string EncodeDouble(double d)
{
    long ieee = System.BitConverter.DoubleToInt64Bits(d);
    ulong widezero = 0;
    ulong lex = ((ieee < 0)? widezero: ((~widezero) >> 1)) ^ (ulong)~ieee;
    return lex.ToString("X16");
}

static double DecodeDouble(string s)
{
    ulong lex = ulong.Parse(s, System.Globalization.NumberStyles.AllowHexSpecifier);
    ulong widezero = 0;
    long ieee = (long)(((0 <= (long)lex)? widezero: ((~widezero) >> 1)) ^ ~lex);
    return System.BitConverter.Int64BitsToDouble(ieee);
}
Run Code Online (Sandbox Code Playgroud)

演示:http://ideone.com/pFciY