кастинг удваивается до целых чисел для получения скорости

в Redis (http://code.google.com/p/redis) там очки, связанные с элементами, для взятия этого отсортированные элементы. Это, которое очки, удваивается, даже если многие пользователи на самом деле вид целыми числами (например, времена Unix).

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

  snprintf((char*)buf+1,sizeof(buf)-1,"%.17g",val);

Дополнительно бесконечность и условия не-числа проверяются, чтобы также представить это в заключительном файле базы данных.

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

Чтобы это обеспечило хорошее ускорение, конечно, тест для целого числа "эквивалентность" должен быть быстрым. Таким образом, я использовал прием, который является, вероятно, неопределенным поведением, но это работало очень хорошо на практике. Что-то как этот:

double x = ... some value ...
if (x == (double)((long long)x))
    use_the_fast_integer_function((long long)x);
else
    use_the_slow_snprintf(x);

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

Поскольку я хотел удостовериться, это не повредит вещи в некоторой системе, я присоединился к #c на freenode, и я получил много оскорблений ;) Таким образом, я теперь пробую здесь.

Существует ли стандартный способ сделать то, что я пытаюсь обойтись без выхода наружу ANSI C? Иначе вышеупомянутый код предположен в настоящее время работать во всех системах Posix это цели Redis? Таким образом, archs, куда Linux / Mac OS X / *BSD / Солярис работают теперешний?

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

Спасибо за любую справку.

9
задан antirez 12 May 2010 в 17:04
поделиться

4 ответа

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

Еще одна мысль - создать собственную функцию snprintf(). Преобразование из double в int изначально поддерживается многими блоками FPU, поэтому оно должно быть молниеносным. Преобразование в строку также просто.

Просто несколько случайных идей для вас.

6
ответ дан 4 December 2019 в 21:48
поделиться

Я не вижу проблем с приведением типов, пока x находится в диапазоне long long. Возможно, вам стоит проверить функцию modf (), которая разделяет двойное число на целую и дробную части. Затем вы можете добавить проверки по (двойному) LLONG_MIN и (двойному) LLONG_MAX для неотъемлемой части, чтобы убедиться. Хотя с точностью double могут возникнуть трудности.

Но прежде чем делать что-либо из этого, вы убедились, что это действительно узкое место, измерив его производительность? И достаточно ли высок процент целочисленных значений, чтобы действительно иметь значение?

1
ответ дан 4 December 2019 в 21:48
поделиться

Ваш тест в порядке (при условии, что к этому моменту вы уже отдельно обрабатывали бесконечности и NAN) - и это, вероятно, один из очень немногих случаев, когда вы действительно действительно ли хотят сравнить числа с плавающей запятой на равенство. Он не вызывает неопределенное поведение - даже если x находится вне диапазона long long , вы просто получите «результат, определенный реализацией», что здесь нормально.

Единственная ложка дегтя состоит в том, что отрицательный ноль в конечном итоге будет положительным (потому что отрицательный ноль сравнивается с положительным нулем).

0
ответ дан 4 December 2019 в 21:48
поделиться

Проблема с этим заключается в том, что сравнения не будут работать так, как вы ожидаете. Тот факт, что одно значение с плавающей запятой меньше другого, не означает, что его представление в виде целого числа будет меньше, чем у другого. Кроме того, я вижу, что вы сравниваете одно из (бывших) двойных значений для равенства. Из-за ошибок округления и представления в битах низкого порядка вы почти никогда не хотите этого делать.

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

2
ответ дан 4 December 2019 в 21:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: