Какой лучший способ представить System.Double сортируемой строкой? - PullRequest
3 голосов
/ 24 июля 2011

В форматах данных, где все базовые типы являются строками, числовые типы должны быть преобразованы в стандартизированный формат строки, который можно сравнивать в алфавитном порядке.Например, short для значения 27 может быть представлено как 00027, если нет негативов.

Каков наилучший способ представления double в виде строки?В моем случае я могу игнорировать негативы, но мне было бы любопытно, как бы вы представляли двойное в любом случае.

ОБНОВЛЕНИЕ

Основываясь на предложении Джона Скита,Я сейчас использую это, хотя я не уверен на 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));
}

ОБНОВЛЕНИЕ 2

Я подтвердил то, что подозревал Джон- негативы не работают с использованием этого метода.Вот пример кода:

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

, который выдает следующий вывод:

09218868437227405311
09214364837600034815
00000000000000000000
18437736874454810623
18442240474082181119

Ясно, не отсортировано, как ожидалось.

ОБНОВЛЕНИЕ 3

Принятый ответ ниже является правильным.Спасибо, ребята!

Ответы [ 3 ]

5 голосов
/ 24 июля 2011

Отступы потенциально довольно неудобны для парных разрядов, учитывая огромный диапазон (double.MaxValue равен 1.7976931348623157E + 308).

Должно ли строковое представление все еще быть читабельным или просто обратимым?

Это дает обратимое преобразование, приводящее к достаточно короткому строковому представлению, сохраняющему лексикографическое упорядочение - но совершенно не очевидно, какое значение double было только из строки.

EDIT: Не используйте 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);
}

Демонстрация здесь: 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);
}

Демонстрация: http://ideone.com/pFciY

1 голос
/ 24 июля 2011

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

Если вы хотите, вы можете даже добавить нормальное представление,поскольку суффикс не влияет на сортировку.

Примеры

E000M3    +3.0
E001M2.7  +27.0

К сожалению, он не работает ни для отрицательных чисел, ни для отрицательных показателей.Вы можете ввести смещение для показателя степени, как если бы формат IEEE использовался внутри.

0 голосов
/ 15 ноября 2013

Как оказалось ... Пакет org.apache.solr.util содержит класс NumberUtils.Этот класс имеет статические методы, которые делают все необходимое для преобразования значений типа double (и других значений данных) в сортируемые строки (и обратно).Методы не могут быть проще в использовании.Несколько замечаний:

  1. Конечно, NumberUtils написан на Java (не на c #).Я думаю, что код может быть преобразован в C # ... Однако я не очень хорошо разбираюсь в C #.Источник доступен в Интернете.
  2. Полученные строки не распечатываются (вообще).
  3. Комментарии в коде указывают, что все экзотические случаи, включая отрицательные числа и бесконечности, должны работать правильно.
  4. Я не делал никаких тестов ... Однако, исходя из быстрого сканирования кода, он должен быть очень быстрым.

Приведенный ниже код показывает, что нужносделано для использования этой библиотеки.

String key = NumberUtils.double2sortableStr(35.2);
...