什么是重新present System.Double作为排序字符串的最佳方式是什么?字符串、方式、present、System

2023-09-04 00:45:38 作者:薍ㄋ兯奏

在数据格式,其中所有基础类型都是字符串,数字类型必须转换为标准化的字符串格式可以按字母顺序进行比较。例如,的值 27 可以重新presented为 00027 如果没有负面影响。

In data formats where all underlying types are strings, numeric types must be converted to a standardized string format which can be compared alphabetically. For example, a short for the value 27 could be represented as 00027 if there are no negatives.

什么是重新present一个作为一个字符串的最好方法是什么?在我来说,我可以忽略底片,但我很好奇,你如何重新present双重无论是哪种情况。

What's the best way to represent a double as a string? In my case I can ignore negatives, but I'd be curious how you'd represent the double in either case.

更新

,我现在用这个,虽然我不是100%肯定它会正常工作:

Based on Jon Skeet's suggestion, I'm now using this, though I'm not 100% sure it'll work correctly:

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

更新2

我已经证实了乔恩怀疑 - 否定不使用这种方法的工作。下面是一些示例code:

I have confirmed what Jon suspected - negatives don't work using this method. Here is some sample code:

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

这将产生以下输出:

Which produces the following output:

09218868437227405311
09214364837600034815
00000000000000000000
18437736874454810623
18442240474082181119

显然不排序预期。

Clearly not sorted as expected.

更新3

下面接受的答案是正确的。谢谢你们!

The accepted answer below is the correct one. Thanks guys!

推荐答案

填充可能是比较尴尬的双打,考虑到巨大的范围( double.MaxValue 是1.7976931348623157E + 308)。

Padding is potentially rather awkward for doubles, given the enormous range (double.MaxValue is 1.7976931348623157E+308).

请问字符串重新presentation仍然是人类可读的,或者只是可逆的?

Does the string representation still have to be human-readable, or just reversible?

这给人一种可逆转换导致相当短的字符串重新presentation preserving字典顺序 - 但它不会在所有显而易见的是什么值只是从字符串。

That gives a reversible conversion leading to a reasonably short string representation preserving lexicographic ordering - but it wouldn't be at all obvious what the double value was just from the string.

编辑:不要的使用 BitConverter.DoubleToInt64Bits 孤单。这颠倒了顺序为负值。

Don't use BitConverter.DoubleToInt64Bits alone. That reverses the ordering for negative values.

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

I'm sure you can perform this conversion using DoubleToInt64Bits and then some bit-twiddling, but unfortunately I can't get it to work right now, and I have three kids who are desperate to go to the park...

为了使一切排序正确,负号需要被存储在那些补格式而不是符号幅值(否则底片和正片的排序中的相对订单),并且符号位需要被翻转(使负的排序小于阳性)。这code应该做的伎俩:

In order to make everything sort correctly, negative numbers need to be stored in ones-complement format instead of sign magnitude (otherwise negatives and positives sort in opposite orders), and the sign bit needs to be flipped (to make negative sort less-than positives). This code should do the trick:

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

示范这里: http://ideone.com/JPNPY

下面是完整的解决方案,并从字符串:

Here's the complete solution, to and from strings:

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

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