Я недавно писал некоторый код для исследовательского проекта, что я продолжаю работать, где эффективность очень важна. Я рассматривал очистку некоторых обычных методов, я выполняю в вещах и использовании поразрядного XORs вместо этого. То, что я задаюсь вопросом, - то, если это сделает, если различие (если я выполняю эту операцию, говорят, что несколько миллионов раз) или если это - то же после того, как я использую 03 в g ++.
Два примера, которые приходят на ум:
У меня был экземпляр, где (я работаю с чисто положительным ints), я должен был изменить n на n-1, если бы n был нечетен или n к (n+1), если n был ровен. Я полагал, что у меня было несколько опций:
if(n%2) // or (n%2==0) and flip the order
n=n-1
else
n=n+1
или
n=n+2*n%2-1; //This of course was silly, but was the only non-bitwise 1 line I could come up with
Наконец:
n=n^1;
Все методы ясно делают то же самое, но мое чувство состояло в том, что третий будет самым эффективным.
Следующий пример находится на более общих сведениях. Скажите, что я сравниваю два положительных целых числа, будет один из них работать лучше, чем другие. Или будет различие действительно не быть примечательным, даже если я выполню эту операцию несколько миллионов раз:
if(n_1==n_2)
if(! (n_1 ^ n_2) )
if( n_1 ^ n_2) else \do work here
Компилятор просто сделает ту же операцию во всех этих экземплярах? Мне просто любопытно, если существует экземпляр, когда я должен использовать битовые операции и не доверять компилятору, чтобы сделать работу для меня.
Fixed:In исправляют оператор проблемы.
Для потоковой передачи и разговора с клиентами необходимо определить протокол: Поиск RTP и RTSP в Интернете. Это должно дать вам довольно хорошее представление о том, что вам нужно, чтобы реализовать эти протоколы или даже создать свой собственный.
Что касается реализации, посмотрите на проект red5: http://red5.org/
Посмотрите также на Xuggler: http://www.xuggle.com/xuggler/ Этот проект поможет вам сохранить много строк кода. Отметим, что его развитие затормозилось.
Ура.
-121--3159578-Операторы Switch работают только на интегральных значениях. Поэтому сообщение об ошибке - «switch quantity not a integer». Я не думаю, что это техническое ограничение настолько, насколько это вне синтаксиса языка.
-121--1453364-Это достаточно легко проверить, просто запустите разборку. Посмотрите:
f.c:
unsigned int f1(unsigned int n)
{
n ^= 1;
return n;
}
unsigned int f2(unsigned int n)
{
if (n % 2)
n=n-1;
else
n=n+1;
return n;
}
Сборка и разборка:
$ cc -O3 -c f.c
$ otool -tV f.o
f.o:
(__TEXT,__text) section
_f1:
00 pushq %rbp
01 movq %rsp,%rbp
04 xorl $0x01,%edi
07 movl %edi,%eax
09 leave
0a ret
0b nopl _f1(%rax,%rax)
_f2:
10 pushq %rbp
11 movq %rsp,%rbp
14 leal 0xff(%rdi),%eax
17 leal 0x01(%rdi),%edx
1a andl $0x01,%edi
1d cmovel %edx,%eax
20 leave
21 ret
Похоже, что f1 ()
немного короче, независимо от того, имеет ли это значение в действительности, зависит от какого-либо эталонного теста.
Является ли n^=1
быстрее, чем if ( n%2 ) --n; else ++n;
? Да. Я бы не ожидал, что компилятор оптимизирует это. Поскольку побитовая операция намного лаконичнее, возможно, стоит ознакомиться с XOR и, возможно, добавить комментарий к этой строке кода.
Если это действительно критично для функциональности вашей программы, это также можно считать проблемой переносимости: если вы тестируете на своем компиляторе, и он работает быстро, то при тестировании на другом компиляторе вас, скорее всего, ждет сюрприз. Обычно это не является проблемой для алгебраических оптимизаций.
Является ли x^y
быстрее, чем x==y
? Нет. Делать что-то окольными путями, как правило, нехорошо.
Мне нужно было изменить n на n-1, если n было четным, или n на (n + 1), если n было нечетным.
В этом случае, независимо от эффективности, n = n ^ 1
неверно .
Для вашего второго случая ==
будет столь же эффективным (если не более), чем любой другой.
В общем, когда дело доходит до оптимизации, вы должны протестировать ее самостоятельно . Если потенциальная оптимизация не заслуживает сравнительного анализа, ее не стоит делать.
Хороший компилятор оптимизирует n%2
, но вы всегда можете проверить ассемблер. Если вы видите деления, начните оптимизировать его самостоятельно, потому что деление - это примерно такой же медленный процесс, как и все остальные.
Вы должны доверять своему компилятору. gcc/++ - это продукт многолетней разработки, и он способен выполнить любую оптимизацию, о которой вы, вероятно, думаете. И, скорее всего, если вы начнете играть, вы испортите его усилия по оптимизации вашего кода.
n ^= 1
и n1==n2
- это, вероятно, лучшее, что вы можете сделать, но на самом деле, если вы стремитесь к максимальной эффективности, не стоит просматривать код в поисках подобных мелочей.
Вот пример того, как действительно настраивать производительность.
Не ждите, что низкоуровневые оптимизации сильно помогут, пока проба не докажет, что именно на них следует сосредоточиться.
Единственный способ узнать наверняка - это проверить. Я должен согласиться с тем, что потребуется довольно умный компилятор, чтобы произвести такой же эффективный вывод для:
if(n%2) // or (n%2==0) and flip the order
n=n-1
else
n=n+1
, как он мог бы для n ^ = 1;
, но я в последнее время не проверял ничего подобного достаточно, чтобы сказать с уверенностью.
Что касается вашего второго вопроса, я сомневаюсь, что это имеет значение - сравнение на равенство быстро завершится для любого из этих методов. Если вам нужна скорость, главное, что нужно сделать, - это вообще не задействовать ветку - например, что-то вроде:
if (a == b)
c += d;
можно записать как: c + = d * (a == b);
. Глядя на язык ассемблера, второй часто выглядит немного запутанным (с уродливой глупостью, чтобы получить результат сравнения флагов в нормальный регистр), но все же часто работает лучше, избегая каких-либо ветвей.
Изменить: по крайней мере, компиляторы, которые у меня есть (gcc и MSVC), не генерируют cmov
для if
, но они создают набор
] для * (a == b)
. Я расширил код до чего-то тестируемого.
Edit2: Поскольку Potatoswatter поднял другую возможность использования поразрядного умножения и вместо умножения, я решил проверить это вместе с другими. Вот код с добавлением:
#include <time.h>
#include <iostream>
#include <stdlib.h>
int addif1(int a, int b, int c, int d) {
if (a==b)
c+=d;
return c;
}
int addif2(int a, int b, int c, int d) {
return c += d * (a == b);
}
int addif3(int a, int b, int c, int d) {
return c += d & -(a == b);
}
int main() {
const int iterations = 50000;
int x = rand();
unsigned tot1 = 0;
unsigned tot2 = 0;
unsigned tot3 = 0;
clock_t start1 = clock();
for (int i=0; i<iterations; i++) {
for (int j=0; j<iterations; j++)
tot1 +=addif1(i, j, i, x);
}
clock_t stop1 = clock();
clock_t start2 = clock();
for (int i=0; i<iterations; i++) {
for (int j=0; j<iterations; j++)
tot2 +=addif2(i, j, i, x);
}
clock_t stop2 = clock();
clock_t start3 = clock();
for (int i=0; i<iterations; i++) {
for (int j=0; j<iterations; j++)
tot3 +=addif3(i, j, i, x);
}
clock_t stop3 = clock();
std::cout << "Ignore: " << tot1 << "\n";
std::cout << "Ignore: " << tot2 << "\n";
std::cout << "Ignore: " << tot3 << "\n";
std::cout << "addif1: " << stop1-start1 << "\n";
std::cout << "addif2: " << stop2-start2 << "\n";
std::cout << "addif3: " << stop3-start3 << "\n";
return 0;
}
Теперь самое интересное: результаты для третьей версии весьма интересны. Для MS VC ++ мы получаем примерно то, что, вероятно, ожидает большинство из нас:
Ignore: 2682925904
Ignore: 2682925904
Ignore: 2682925904
addif1: 4814
addif2: 3504
addif3: 3021
Использование &
вместо *
дает определенное улучшение - почти ] такое же улучшение, как *
уступает if
. С gcc результат немного отличается:
Ignore: 2680875904
Ignore: 2680875904
Ignore: 2680875904
addif1: 2901
addif2: 2886
addif3: 7675
В этом случае код, использующий if
, намного ближе к скорости кода, использующего *
, но код, использующий &
медленнее любого из них - на много медленнее! В случае, если кому-то интересно, я нашел это достаточно удивительным, что я пару раз перекомпилировал с разными флагами, повторно запускал несколько раз с каждым и так далее, и результат был полностью согласован - код, использующий &
всегда был значительно медленнее.
Плохой результат с третьей версией кода, скомпилированной с помощью gcc, возвращает нас к тому, что я сказал начать с [и заканчивает это редактирование]:
Как я сказал вначале, «единственный способ узнать о конечно, это проверка "- но, по крайней мере, в этом ограниченном тестировании умножение последовательно превосходит if
. Может быть некоторая комбинация компилятора, флагов компилятора, ЦП, шаблона данных, количества итераций и т. Д., Которая благоприятствует if
умножению - нет никаких сомнений в том, что разница достаточно мал, чтобы испытание, идущее в другом направлении, было вполне правдоподобным. Тем не менее, я считаю, что эту технику стоит знать; для основных компиляторов и процессоров он кажется достаточно эффективным (хотя он определенно более полезен с MSVC, чем с gcc).
[возобновление edit2:] результат с использованием gcc и
демонстрирует степень, в которой 1) микрооптимизации могут быть / являются специфичными для компилятора и 2) насколько реальные результаты могут отличаться от ожиданий.