Для точного соответствия наиболее целесообразно использовать ==
. Кроме того, это будет быстрее, чем grep()
, и, очевидно, намного проще.
which(string == "apple")
# [1] 1
Python:
time python -c 'for i in xrange(int(1e8)): t=12341234234.234 / 2.0'
real 0m26.676s
user 0m25.154s
sys 0m0.076s
time python -c 'for i in xrange(int(1e8)): t=12341234234.234 * 0.5'
real 0m17.932s
user 0m16.481s
sys 0m0.048s
умножение на 33% быстрее
Lua:
time lua -e 'for i=1,1e8 do t=12341234234.234 / 2.0 end'
real 0m7.956s
user 0m7.332s
sys 0m0.032s
time lua -e 'for i=1,1e8 do t=12341234234.234 * 0.5 end'
real 0m7.997s
user 0m7.516s
sys 0m0.036s
=> никакая реальная разница
LuaJIT:
time luajit -O -e 'for i=1,1e8 do t=12341234234.234 / 2.0 end'
real 0m1.921s
user 0m1.668s
sys 0m0.004s
time luajit -O -e 'for i=1,1e8 do t=12341234234.234 * 0.5 end'
real 0m1.843s
user 0m1.676s
sys 0m0.000s
=> это только на 5% быстрее
заключения: в Python это быстрее для умножения, чем разделиться, но поскольку Вы становитесь ближе к ЦП с помощью более усовершенствованного VMs или МОНЕТ В ПЯТЬ ЦЕНТОВ, преимущество исчезает. Довольно возможно, что будущий Python VM сделал бы его не важным
Ну, если мы предполагаем, что добавить/подотследить операция стоит 1, затем умножьте затраты 5 и разделите затраты приблизительно 20.
Я предложил бы умножение в целом, потому что Вы не должны тратить циклы, гарантирующие, что Ваш делитель не 0. Это не применяется, конечно, если Ваш делитель является константой.
Я читал где-нибудь, что умножение более эффективно в C/C++; Никакая идея относительно интерпретируемых языков - различие не, вероятно, незначительна из-за всех других издержки.
, Если это не становится палкой проблемы с тем, что более удобно в сопровождении/читаемо - я ненавижу его, когда люди говорят мне это, но таким образом верный.
Опасайтесь "предполагать, что умножение обычно лучше, таким образом, я пытаюсь придерживаться этого, когда я кодирую",
В контексте этого конкретного вопроса, лучше здесь означает "быстрее". Который не очень полезен.
Взгляды о скорости могут быть серьезной ошибкой. Существуют глубокие ошибочные последствия в определенной алгебраической форме вычисления.
См. арифметика С плавающей точкой с анализом ошибок . См. Важные вопросы в Арифметике С плавающей точкой и Анализе ошибок .
, В то время как некоторые значения с плавающей точкой точны, большинство значений с плавающей точкой является приближением; они - некоторое идеальное значение плюс некоторая ошибка. Каждая операция относится к идеальному значению и ошибочному значению.
самые большие проблемы возникают из попытки управлять двумя почти-равными-количествами. Самые правые биты (биты ошибки) прибывают для доминирования над результатами.
>>> for i in range(7):
... a=1/(10.0**i)
... b=(1/10.0)**i
... print i, a, b, a-b
...
0 1.0 1.0 0.0
1 0.1 0.1 0.0
2 0.01 0.01 -1.73472347598e-18
3 0.001 0.001 -2.16840434497e-19
4 0.0001 0.0001 -1.35525271561e-20
5 1e-05 1e-05 -1.69406589451e-21
6 1e-06 1e-06 -4.23516473627e-22
В этом примере, Вы видите, что, поскольку значения становятся меньшими, различие почти между равными количествами создают ненулевые результаты, где корректный ответ является нулем.
Это становится большим количеством вопроса, когда Вы программируете в блоке или возможно C. Я полагаю, что с наиболее современными языками, что оптимизация, такая как это делается для меня.
Подразделение с плавающей точкой является (обычно) особенно медленным, поэтому в то время как умножение с плавающей точкой является также относительно медленным, это, вероятно, быстрее, чем подразделение с плавающей точкой.
, Но я более склонен ответить, что "это действительно не имеет значения", если профилирование не показало, что подразделение является небольшим узким местом по сравнению с умножением. Я предполагаю, тем не менее, что выбор умножения по сравнению с подразделением не собирается оказывать большое влияние производительности в Вашем приложении.
Умножение обычно быстрее - конечно, никогда медленнее. Однако, если это не очень важная скорость, запишите, какой бы ни является самым ясным.
Если Вы работаете с целыми числами или не типы, с плавающей точкой не забывают Ваших bitshifting операторов: < <>>
int y = 10;
y = y >> 1;
Console.WriteLine("value halved: " + y);
y = y << 1;
Console.WriteLine("now value doubled: " + y);
Сделайте то, в чем Вы нуждаетесь. Думайте о своем читателе сначала, не волнуйтесь о производительности, пока Вы не уверены, что у Вас есть проблема производительности.
Позволяют компилятору сделать производительность для Вас.
Запишите, какой бы ни более ясно состояния Ваше намерение.
После Ваших работ программы, выясните то, что является медленным, и сделайте это быстрее.
не делают этого наоборот.
Если Вы хотите оптимизировать свой код, но все еще ясны, попробуйте это:
y = x * (1.0 / 2.0);
компилятор должен быть в состоянии сделать деление во время компиляции, таким образом, Вы получаете умножение во времени выполнения. Я ожидал бы, что точность совпадет с в y = x / 2.0
случай.
то, Где это может иметь БОЛЬШОЕ ЗНАЧЕНИЕ, находится во встроенных процессорах, где эмуляция с плавающей точкой требуется, чтобы вычислять арифметику с плавающей точкой.
Умножение быстрее, подразделение более точно. Вы потеряете некоторую точность, если Ваше число не будет питанием 2:
y = x / 3.0;
y = x * 0.333333; // how many 3's should there be, and how will the compiler round?
, Даже если Вы позволяете компилятору выяснить инвертированную константу к идеальной точности, ответ может все еще отличаться.
x = 100.0;
x / 3.0 == x * (1.0/3.0) // is false in the test I just performed
проблема скорости, вероятно, будет, только иметь значение в C/C++ или языках JIT, и даже тогда, только если операция находится в цикле в узком месте.
Я думаю, что это добирается так nitpicky, что Вы были бы более обеспеченным выполнением, вообще делает код более читаемым. Если Вы не выполняете операции тысячи, если не миллионы, времен, я сомневаюсь, что любой будет когда-либо замечать различие.
, Если действительно необходимо сделать выбор, сравнительное тестирование является единственным способом пойти. Найдите, какая функция (функции) дают Вам проблемы, затем узнают, где в функции проблемы происходят и фиксируют те разделы. Однако я все еще сомневаюсь, что единственная математическая операция (даже каждый повторил многих, много раз) будет причина любого узкого места.
Я всегда узнавал, что умножение более эффективно.
Всегда используйте то, что является самым ясным. Что-либо еще, что Вы делаете, пытается перехитрить компилятор. Если компилятор будет вообще интеллектуален, он приложит все усилия для оптимизации результата, но ничто не может заставить следующего парня не ненавидеть Вас за Ваше дрянное bitshifting решение (я люблю побитовую обработку между прочим, это интересно. Но забава! = читаемый)
Преждевременная оптимизация является корнем всего зла. Всегда помните три правила оптимизации!
, Если Вы - эксперт и можете выровнять по ширине потребность, затем используйте следующую процедуру:
кроме того, делая вещи как удаление внутренних циклов, когда они не требуются, или предпочитание связанного списка по массиву для вида вставки не оптимизация, просто программируя.
Просто собираюсь добавить кое-что для опции "другие языки".
C: Так как это просто академическое упражнение, которое на самом деле не имеет значения, я подумал, что внес бы что-то другое.
Я скомпилировал для сборки без оптимизации и посмотрел на результат.
.
Код:
int main() {
volatile int a;
volatile int b;
asm("## 5/2\n");
a = 5;
a = a / 2;
asm("## 5*0.5");
b = 5;
b = b * 0.5;
asm("## done");
return a + b;
}
скомпилирован с gcc tdiv.c -O1 -o tdiv.s -S
делением на 2:
movl $5, -4(%ebp)
movl -4(%ebp), %eax
movl %eax, %edx
shrl $31, %edx
addl %edx, %eax
sarl %eax
movl %eax, -4(%ebp)
и умножением на 0. 5:
movl $5, -8(%ebp)
movl -8(%ebp), %eax
pushl %eax
fildl (%esp)
leal 4(%esp), %esp
fmuls LC0
fnstcw -10(%ebp)
movzwl -10(%ebp), %eax
orw $3072, %ax
movw %ax, -12(%ebp)
fldcw -12(%ebp)
fistpl -16(%ebp)
fldcw -10(%ebp)
movl -16(%ebp), %eax
movl %eax, -8(%ebp)
Однако, когда я изменил эти int
s на double
s (что, вероятно, и сделал бы питон), я получил следующее:
деление:
flds LC0
fstl -8(%ebp)
fldl -8(%ebp)
flds LC1
fmul %st, %st(1)
fxch %st(1)
fstpl -8(%ebp)
fxch %st(1)
умножение:
fstpl -16(%ebp)
fldl -16(%ebp)
fmulp %st, %st(1)
fstpl -16(%ebp)
я не сравнивал ни один из этих кодов, но, просто просмотрев код, можно увидеть, что при использовании целых чисел деление на 2 короче, чем умножение на 2. При использовании удвоений умножение короче, так как компилятор использует опкоды с плавающей запятой процессора, которые, вероятно, работают быстрее (но на самом деле я не знаю), чем не используют их для той же самой операции. Так что в конечном итоге этот ответ показал, что производительность умножения на 0.5 против деления на 2 зависит от реализации языка и платформы, на которой он работает. В конце концов, разница ничтожно мала, и о ней практически никогда не стоит беспокоиться, кроме как о читабельности.
В качестве примечания можно заметить, что в моей программе main()
возвращает a + b
. Когда я убираю волатильное ключевое слово, вы никогда не догадаетесь, как выглядит ассемблер (исключая настройку программы):
## 5/2
## 5*0.5
## done
movl $5, %eax
leave
ret
она делала и деление, и умножение, и сложение в одной команде! Очевидно, что вам не стоит беспокоиться об этом, если оптимизатор какой-то респектабельный.
Извините за слишком длинный ответ.