Форум русскоязычного сообщества Ubuntu


Получить помощь и пообщаться с другими пользователями Ubuntu можно
на irc канале #ubuntu-ru в сети Freenode
и в Jabber конференции ubuntu@conference.jabber.ru

Автор Тема: Си. Быстрый вывод данных  (Прочитано 2879 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн victor00000

  • Старожил
  • *
  • Сообщений: 15568
  • Глухонемой (Deaf)
    • Просмотр профиля
Re: Си. Быстрый вывод данных
« Ответ #30 : 06 Мая 2014, 20:39:52 »

1
dd if=/dev/zero of=/dev/null bs=1 count=1M
2
dd if=/dev/zero of=/dev/null bs=1M count=1

кто первый?
Wars ~.o

Оффлайн inkblack

  • Старожил
  • *
  • Сообщений: 1216
    • Просмотр профиля
Re: Си. Быстрый вывод данных
« Ответ #31 : 06 Мая 2014, 21:37:26 »
Код: (bash) [Выделить]
sol@eee:~$ dd if=/dev/zero of=/dev/null bs=1 count=1M
1048576+0 записей получено
1048576+0 записей отправлено
скопировано 1048576 байт (1,0 MB), 1,21919 c, 860 kB/c
sol@eee:~$ dd if=/dev/zero of=/dev/null bs=1M count=1
1+0 записей получено
1+0 записей отправлено
скопировано 1048576 байт (1,0 MB), 0,00123691 c, 848 MB/c

Это очевидно. Но та прога, о которой мы говорим, не очень-то много печатает.
Разница в скорости будет абсолютно незаметна.
Делюсь знаниями, но их у меня мало!

Оффлайн victor00000

  • Старожил
  • *
  • Сообщений: 15568
  • Глухонемой (Deaf)
    • Просмотр профиля
Re: Си. Быстрый вывод данных
« Ответ #32 : 06 Мая 2014, 22:07:41 »
inkblack,
да.

bs - это printf
count - это for
Wars ~.o

Оффлайн unimix

  • Активист
  • *
  • Сообщений: 537
    • Просмотр профиля
Re: Си. Быстрый вывод данных
« Ответ #33 : 06 Мая 2014, 22:12:12 »
Кстати, вот неочевидный индусский вариант:
Код: (c) [Выделить]
#include <stdio.h>

unsigned long int max;
unsigned long int power;

int getdivnumb(numb) {
    unsigned long int i, j, divnumb;
    divnumb = 2;

    for (i = 2, j = numb/2 + 1; i <= j; i++, j--) {
        if (numb % i == 0) {
            divnumb++;
            if (divnumb > power) {
                return 0;
            }
        }
        if (numb % j == 0) {
            divnumb++;
            if (divnumb > power) {
                return 0;
            }
        }
        if (i == j) {
            break;
        }
    }
    return divnumb == power;
}

main(int argc, char *argv[]) {
    unsigned long int i;
    max = atol(argv[2]);
    power = atol(argv[3]);

    for (i = atol(argv[1]); i < max; i++) {
        if (getdivnumb(i)) {
            printf("%lu\n",i);
        }
    }
}

Этот код производительнее изначального уже более, чем в 8 раз (при вызове с аргументами "2 200000 3").

Оффлайн victor00000

  • Старожил
  • *
  • Сообщений: 15568
  • Глухонемой (Deaf)
    • Просмотр профиля
Re: Си. Быстрый вывод данных
« Ответ #34 : 06 Мая 2014, 22:20:21 »
victor00000, может уберешь из своей подписи
<img src="http://vict1971.mooo.com/v.gif" alt="" class="bbc_img" />
Не грузится картинка :(

ок. )))
Wars ~.o

Оффлайн alexander.pronin

  • Старожил
  • *
  • Сообщений: 2539
    • Просмотр профиля
Re: Си. Быстрый вывод данных
« Ответ #35 : 07 Мая 2014, 09:12:26 »
Код: (bash) [Выделить]
sol@eee:~$ dd if=/dev/zero of=/dev/null bs=1 count=1M
1048576+0 записей получено
1048576+0 записей отправлено
скопировано 1048576 байт (1,0 MB), 1,21919 c, 860 kB/c
sol@eee:~$ dd if=/dev/zero of=/dev/null bs=1M count=1
1+0 записей получено
1+0 записей отправлено
скопировано 1048576 байт (1,0 MB), 0,00123691 c, 848 MB/c
Это очевидно.
При записи на диск даже 1 байта будет писаться (переписываться) все равно 1 сектор.
Поэтому, в общем случае, буферизация необходима.

Оффлайн inkblack

  • Старожил
  • *
  • Сообщений: 1216
    • Просмотр профиля
Re: Си. Быстрый вывод данных
« Ответ #36 : 07 Мая 2014, 12:17:46 »
Цитировать
Код: (bash) [Выделить]
... of=/dev/null
Какой диск?  :D

В общем-то все всё понимают, операции ввода-вывода могут довольно сильно
замедлить исполнение программы. Просто иногда мы тут как-то неясно формулируем
свои соображения, а другие собеседники неверно интерпретируют...

Между прочим, почитайте вот K&R, у меня во втором издании (1992) — стр. 170:

8.5. Пример. Реализация функций fopen и getc

Программист просто обязан это знать.
Делюсь знаниями, но их у меня мало!

Оффлайн unimix

  • Активист
  • *
  • Сообщений: 537
    • Просмотр профиля
Re: Си. Быстрый вывод данных
« Ответ #37 : 07 Мая 2014, 12:40:19 »
Код в предыдущем сообщении, которое я удалил, также содержал ошибку: не просчитывал простые числа.
Первый вариант кода плох тем, что при увеличении значения power, скорость вычислений приближается к скорости вычислений оригинального кода ТС. Также он всё-равно медленнее, чем здесь.
Индусский вариант кода как и полагается, правильно работает только с тестовой задачей (когда power=3). Вообще не понятно, как он ускорил вычисления по сравнению с первым выариантом.

Вот более правильный вариант оптимизации:
Код: (c) [Выделить]
#include <stdio.h>

unsigned long int max;
unsigned long int power;

int getdivnumb(numb) {
    unsigned long int i, k, divnumb;
    divnumb = 2;
    k = numb/2 + 1;

    for (i = 2; i < k; i++) {
        if (numb % i == 0) {
            divnumb++;

            k = numb / i;
            if (k > i) {
                divnumb++;
            }

            if (divnumb > power) {
                return 0;
            }
        }
    }

    return divnumb == power;
}

main(int argc, char *argv[]) {
    unsigned long int i;
    max = atol(argv[2]);
    power = atol(argv[3]);

    for (i = atol(argv[1]); i < max; i++) {
        if (getdivnumb(i)) {
            printf("%lu\n",i);
        }
    }
}

Скорость, по сравнению с оригинальным кодом ТС, для max=200000:
power=2 увеличена в 15.5 раз (простые числа)
power=3 увеличена в 15.5 раз
power=4 увеличена в 7.8 раз
power=5 увеличена в 7.8 раз
power=6 увеличена в 7.2 раз

Оффлайн alexander.pronin

  • Старожил
  • *
  • Сообщений: 2539
    • Просмотр профиля
Re: Си. Быстрый вывод данных
« Ответ #38 : 07 Мая 2014, 13:42:01 »
Цитировать
Код: (bash) [Выделить]
... of=/dev/null
Какой диск?  :D
Согласен.
Правильнее 'блочное устройство',
хотя с диском звучит более конкретно.
« Последнее редактирование: 07 Мая 2014, 13:44:55 от alexander.pronin »

Оффлайн SkinnyJack

  • Любитель
  • *
  • Сообщений: 53
    • Просмотр профиля
Re: Си. Быстрый вывод данных
« Ответ #39 : 07 Мая 2014, 14:08:54 »
На Си давно не писал, но хочу высказать
свою скромную точку мнения.
Нужен быстрый вывод (куда угодно) -
- ассемблер в руки, несколько подпрограмм,
и вопрос будет решен.
Тем более и Си и ассемблер очень хорошо
соединяются.
(Как вариант - пишите на Форте - результат будет точно).
Какая разница? В конце концов, это всё равно окажется write.

Оффлайн hon

  • Автор темы
  • Старожил
  • *
  • Сообщений: 1044
  • Ubuntu 12.04 LTS
    • Просмотр профиля
Re: Си. Быстрый вывод данных
« Ответ #40 : 07 Мая 2014, 21:35:51 »
inkblack, спасибо. Когда дойду до 8.5 буду оптимизировать printf.
unimix, спасибо за код. Сейчас привел его к варианту ниже.
Не существует натурального числа N, для которого которого N⋮N/2+1, если N≠N/2+1, поэтому достаточно писать k=numb/2.
Что делает код между комментариями /* ? ? ? */ ?

Код: (c) [Выделить]
#include <stdio.h>

unsigned long power;

unsigned long getdivnumb(numb) {
    unsigned long i, k, divnumb;
    divnumb = 2;
    k = numb / 2;
 
    for (i = 2; i < k; i++) {
        if (numb % i == 0) {
            divnumb++;
            /* ? ? ? */
            k = numb / i;
            if (k > i) divnumb++;
            /* ? ? ? */
            if (divnumb > power) return 0;
        }
    }
 
    return divnumb == power;
}
main(int argc, char *argv[]) {
  unsigned long i;
  unsigned long max = atol(argv[2]);
  power = atol(argv[3]);
 
  for (i = atol(argv[1]); i < max; i++) {
      if (getdivnumb(i,power)) printf("%lu\n",i);
  }
}

Оффлайн unimix

  • Активист
  • *
  • Сообщений: 537
    • Просмотр профиля
Re: Си. Быстрый вывод данных
« Ответ #41 : 07 Мая 2014, 22:09:00 »
Да там надо было привести к циклу do-while, просто лень было. Вот и сделал k = numb / 2 + 1, чтобы при первом заходе k всегда была больше 2. Так что, если убираешь +1, то переделай в do-while.

Насчёт кода внутри цикла. Тут используется уменьшение k, чтобы не было лишних поисков. Например, число 100 делится на 2, но также делится на 50, делиться на 4, но также на 25 и т.д. При делении на 2 без остатка понятно, что есть 2 делителя, а искать свыше 50 будет лишним, при делении на 4 без остатка понятно, что есть 2 делителя, а больше 25 уже нет, так как 50 уже посчитали. Вот и идёт инкремент divnumb в случае, если numb/i больше i (в случае, когда numb/i равно i инкремент не происходит, например 9/3==3).

Если знать особенности начального и конечного значений поиска, то возможно ускорить работу используя кэш. Например, в каком диапазоне предполагаются начальные значения (argv[1]) в разных запусках программы?

Думаю, что и этот код не оптимизирован достаточно.
« Последнее редактирование: 07 Мая 2014, 22:22:56 от unimix »

Оффлайн unimix

  • Активист
  • *
  • Сообщений: 537
    • Просмотр профиля
Re: Си. Быстрый вывод данных
« Ответ #42 : 09 Мая 2014, 04:29:31 »
hon, оптимизируй код с моей подсказкой и получишь очень хорошее увеличение скорости по сравнению с начальным кодом.

Я вот потестил и у меня получилось:
start=2 max=200000 power=2 (простые числа)
начальный код: real 1m34.848s (94.848s)
оптимиз. код: real 0m0.112s
Cкорость увеличилась более, чем в 800 раз.

start=2 max=200000 power=3
начальный код: real 1m34.848s (94.848s)
оптимиз. код: real 0m0.110s
Cкорость увеличилась более, чем в 800 раз.

start=2 max=200000 power=4
начальный код: real 1m34.848s (94.848s)
оптимиз. код: real 0m0.306s
Cкорость увеличилась более, чем в 300 раз.

start=2 max=200000 power=5
начальный код: real 1m34.848s (94.848s)
оптимиз. код: real 0m0.303s
Cкорость увеличилась более, чем в 300 раз.

Вообще-то даже сложно считать производительность, так как слишком быстрый просчёт до 200000.
А ты всё про оптимизацию printf с приростом в 20-30 раз. =)
« Последнее редактирование: 09 Мая 2014, 04:39:29 от unimix »

Оффлайн hon

  • Автор темы
  • Старожил
  • *
  • Сообщений: 1044
  • Ubuntu 12.04 LTS
    • Просмотр профиля
Re: Си. Быстрый вывод данных
« Ответ #43 : 09 Мая 2014, 21:37:22 »
unimix,
Предполагается, что значения min и max (argv[1] и argv[2]) в диапазоне 2..2^32-1.
Цитировать
hon, оптимизируй код с моей подсказкой и получишь очень хорошее увеличение скорости по сравнению с начальным кодом.
Ускорение в сотни раз в последнем посте — это с сохранением чисел в оперативке (кеш)?

Оффлайн SergeyIT

  • Зануда.
  • Заслуженный пользователь
  • Старожил
  • *
  • Сообщений: 5753
  • Все по палатам!
    • Просмотр профиля
Re: Си. Быстрый вывод данных
« Ответ #44 : 09 Мая 2014, 21:48:23 »
Ускорение в сотни раз в последнем посте — это с сохранением чисел в оперативке (кеш)?
C printf и без время выполнения одно и то же в секундах (./a.out 2 100000 3 > a.txt ) - 8 сек.
Извините, я все еще учусь

 

Страница сгенерирована за 0.02 секунд. Запросов: 21.