Блог пользователя OSt

Автор OSt, 14 лет назад, По-русски

Здравствуйте. Решил поделиться со всеми своими наработками в области оценки скорости работы одной часто используемой в задачах вещи - форматированным выводом дробных чисел на Java.

Задача: вывод double с 4 знаками после разделителя.

Алгоритмы:

1. printf(Locale.US, "%.4f", num);

2.

long l = Math.round(number*10000);
print(l/10000+"."); // вывод целой части и разделителя
printf("%04d", l%10000); // вывод дробной части с ведущими нулями если потребуется

3.

long l = Math.round(numbers[j] * 10000);
print(l / 10000 + ".");// вывод целой части и разделителя
l %= 10000;
for (int d = 1000; d >= 10; d /= 10) {
if (l < d) {
print(0);
  }
}
  println(l);

Железо : Процессор: Intel Core 2 Duo 2ГГц, 2ГГб оперативной памяти. 

Софт : jdk1.6.0 update 14, jre1.6.0 update 14.

Результаты:

В столбиках (Число чисел для вывода | Время работы 1 алгоритма в сек. |Время работы 2 алгоритма | Время работы 3 алгоритма | Отношение времени 1 алгоритма ко второму | Отношение времени работы 1 алгоритма к 3 алгоритму)   

20000 0.125 0.062 0.016 2,0161 7,8125
30000 0.141 0.125 0.031 1,1280 4,5484
40000 0.234  0.188 0.062 1,2447 3,7742
50000 0.547 0.234 0.063 2,3376 8,682
90000 0.703 0.469 0.141 1,4989 4,9858
100000 0.938 0.625 0.156 1,5008 6,0128
110000 1.093 0.703 0.172 1,5548 6,3547
120000 1.219 0.812 0.188 1,5012 6,4840
140000 1.656 1.141 0.218 1,4514 7,5963

190000 1.75 1.266 0.312 1,3823 5,6090

Как видно из результатов последний алгоритм "рвет" первые 2 более чем в 4 раза. Хотя пишется не на много дольше первые двух.Я уже один раз попался на такой крючок, после чего и провёл эти опыты.

Надеюсь, мои наблюдения кому-нибудь пригодятся.

PS: Иногда помимо основных данных с форматом надо выводить это в несколько строк.

Чтобы не писать извраты типа: 

printf(%.4f,num);

println();

printf(%.4f,num2);

или просто вывод \n  можно почитать тот же javaDос и узнать, что это можно сделать так -   out.printf("%.4f%n%.4f", num,num2); По-моему  - куда лучшее решение.

  • Проголосовать: нравится
  • 0
  • Проголосовать: не нравится

14 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Обычно грамотные авторы задач стараются сделать так, чтобы вывод можно было осуществить стандартными средствами языка. 
  • 14 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Но, к сожалению, иногда даже на acm.sgu.ru приходиться тратить немало времени на технические нюансы ввода/вывода, чтобы обойти TL, причем при оптимальном решении... ;( У меня такое было когда я по своей наивности пытался использовать стандартные cin cout
    • 14 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      Сожалеть тут можно только о дизайне библиотек, а не о задачах.

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

      • 14 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится
        Не стоит полагаться "на всё готовинькое". Все компиляторы и т.п. тоже писались людьми. Перед ними тоже ставились задачи, с которыми они просто справились хуже, чем Вы об этом думали. Так что побыть в роли создателя крутых алгоритмов для чтения данных и их обработки тоже иногда полезно. Лучше начинаешь понимать глубокие технические вещи.
        • 14 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится
          Для понимания технических вещей нужно писать на ассемблере, а не обходить багофичи Явы.
14 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Просто парсинг форматной строки внутри цикла, - видимо, дело не очень эффективное.

Так, возможно, будет лучше:
DecimalFormat formatter = new DecimalFormat("##0.####");
for (int i = 0; i < numbers.length(); ++i)
System.out.println(formatter.format(numbers[i]));