Перевага переключення на оператор if-else


168

Яка найкраща практика використання switch оператора проти використання ifоператора для 30 unsignedперерахувань, де приблизно 10 мають очікувані дії (на даний момент це та сама дія). Продуктивність та простір потрібно враховувати, але вони не є критичними. Я абстрагував фрагмент, тому не ненавиджу мене за умовами іменування.

switch заява:

// numError is an error enumeration type, with 0 being the non-error case
// fire_special_event() is a stub method for the shared processing

switch (numError)
{  
  case ERROR_01 :  // intentional fall-through
  case ERROR_07 :  // intentional fall-through
  case ERROR_0A :  // intentional fall-through
  case ERROR_10 :  // intentional fall-through
  case ERROR_15 :  // intentional fall-through
  case ERROR_16 :  // intentional fall-through
  case ERROR_20 :
  {
     fire_special_event();
  }
  break;

  default:
  {
    // error codes that require no additional action
  }
  break;       
}

if заява:

if ((ERROR_01 == numError)  ||
    (ERROR_07 == numError)  ||
    (ERROR_0A == numError)  || 
    (ERROR_10 == numError)  ||
    (ERROR_15 == numError)  ||
    (ERROR_16 == numError)  ||
    (ERROR_20 == numError))
{
  fire_special_event();
}

26
Це редагується як "суб'єктивне"? Дійсно? Безумовно, "суб'єктивним" є речі, які не можна довести так чи інакше?
Олександра Франкс

Впевнені, що ви бачите це з того місця, в якому генерується найефективніший код, але будь-який сучасний компілятор повинен бути однаково ефективним. Зрештою, це більше питання про колір сараю велосипеда.
jfs

8
Я не згоден, я не думаю, що це суб'єктивно. Проста різниця ASM має значення, ви не можете просто нехтувати кількома секундами оптимізації у багатьох випадках. І в цьому питанні це не релігійна війна чи дебати, є раціональне пояснення, чому можна було б швидше, просто прочитайте прийняту відповідь.
чакрит


@RichardFranks offtopic: грати! ти перша людина, яка взяла на себе модерацію на ЗО, яку я коли-небудь бачив
ТА, яку

Відповіді:


162

Використовуйте перемикач.

У гіршому випадку компілятор генерує той самий код, що і ланцюг if-else, тому ви нічого не втрачаєте. Якщо ви сумніваєтеся, поставте найчастіші випадки спочатку в оператор переключення.

У кращому випадку оптимізатор може знайти кращий спосіб генерування коду. Загальні речі, які робить компілятор - це побудувати бінарне дерево рішень (зберігає порівняння та стрибки у середньому випадку) або просто побудувати таблицю стрибків (працює без порівняння взагалі).


2
Технічно все ще буде одне порівняння, щоб переконатися, що значення перерахунку лежить у таблиці стрибків.
0124816

Джип. Це правда. Якщо ввімкнути перерахунки та вирішити всі випадки, можливо, можна позбутися останнього порівняння.
Нільс Піпенбрінк

4
Зауважте, що ряд ifs теоретично може бути проаналізований таким, що відповідає переключенню компілятором, але навіщо ризикувати? За допомогою перемикача ви повідомляєте саме те, що хочете, що полегшує генерацію коду.
jakobengblom2

5
jakoben: Це можна зробити, але лише для ланцюжків, як-от комутаторів, якщо / ще. На практиці це не відбувається, оскільки програмісти використовують перемикач. Я заглибився в компіляторну технологію і мені довіряють: Пошук таких "непотрібних" конструкцій займає багато часу. Для хлопців-компіляторів така оптимізація має сенс.
Нілс Піпенбрінк

5
@NilsPipenbrinck завдяки простоті побудови псевдорекурсивних if- elseланцюжків у мета-програмуванні шаблонів та труднощі створення switch caseланцюгів, що відображення може стати важливішим. (і так, стародавній коментар, але Інтернет є назавжди або принаймні до наступного вівторка)
Якк - Адам Невраумон

45

Для особливого випадку, який ви вказали у своєму прикладі, мабуть, найясніший код:

if (RequiresSpecialEvent(numError))
    fire_special_event();

Очевидно, це просто переміщує проблему в іншу область коду, але тепер у вас є можливість повторно використовувати цей тест. Ви також маєте більше варіантів, як це вирішити. Ви можете використовувати std :: set, наприклад:

bool RequiresSpecialEvent(int numError)
{
    return specialSet.find(numError) != specialSet.end();
}

Я не припускаю, що це найкраща реалізація RequiresSpecialEvent, тільки що це варіант. Ви все ще можете використовувати комутатор або ланцюжок if-else, або таблицю пошуку, або якусь біт-маніпуляцію зі значенням, будь-яке. Чим незрозумілішим стає ваш процес прийняття рішень, тим більше значення ви отримаєте від того, щоб мати його в ізольованій функції.


5
Це так правда. Читання читачів набагато краще, ніж як перемикач, так і твердження if. Я насправді збирався відповісти щось подібне сам, але ти мене на це побив. :-)
mlarsen

Якщо ваші значення перерахунків невеликі, вам не потрібен хеш, а лише таблиця. наприклад, const std::bitset<MAXERR> specialerror(initializer); Використовуйте його if (specialerror[numError]) { fire_special_event(); }. Якщо ви хочете перевірити межі, bitset::test(size_t)викинете виняток із значень поза межами. ( bitset::operator[]не перевіряє діапазон). cplusplus.com/reference/bitset/bitset/test . Це, ймовірно, перевершить реалізацію створеної компілятором таблиці стрибків switch, особливо у не особливому випадку, коли це буде окрема незайнята гілка.
Пітер Кордес

@PeterCordes Я все ще стверджую, що краще поставити таблицю у власну функцію. Як я вже сказав, є багато варіантів, які відкриваються, коли ти це робиш, я не намагався їх перерахувати.
Марк Викуп 11

@MarkRansom: Я не хотів погодитися з абстрагуванням цього. Оскільки я дав вибірку реалізації std::set, я вважав, що це, мабуть, поганий вибір. Виявляється, gcc вже компілює код OP для тестування растрової карти в 32-бітовому режимі негайно. godbolt: goo.gl/qjjv0e . gcc 5.2 навіть зробить це для ifверсії. Крім того, більш недавні gcc використовуватимуть інструкцію біт-тесту btзамість зсуву, щоб помістити 1трохи в потрібне місце і використовувати test reg, imm32.
Пітер Кордес

Цей негайний постійний растровий малюнок - це великий виграш, тому що в растровій мапі немає жодного пропуску кешу. Він працює, якщо "спеціальні" коди помилок знаходяться в діапазоні 64 або менше. (або 32 для застарілого 32-бітового коду.) Компілятор віднімає найменше значення регістру, якщо воно не нульове. Висновок полягає в тому, що останні компілятори досить розумні, що ви, ймовірно, збираєтеся отримати хороший код з будь-якої логіки, яку ви використовуєте, якщо ви не скажете йому використовувати об'ємну структуру даних.
Пітер Кордес

24

Вимикач є швидше.

Просто спробуйте, якщо / інше 30 різних значень всередині циклу, і порівняйте його з тим самим кодом за допомогою перемикача, щоб побачити, наскільки швидше відбувається перемикання.

Тепер у перемикача є одна реальна проблема : комутатор повинен знати під час компіляції значення всередині кожного випадку. Це означає, що наступний код:

// WON'T COMPILE
extern const int MY_VALUE ;

void doSomething(const int p_iValue)
{
    switch(p_iValue)
    {
       case MY_VALUE : /* do something */ ; break ;
       default : /* do something else */ ; break ;
    }
}

не компілюється

Більшість людей тоді використовуватиме визначення (Aargh!), А інші оголошуватимуть та визначатимуть постійні змінні в одній і тій же одиниці компіляції. Наприклад:

// WILL COMPILE
const int MY_VALUE = 25 ;

void doSomething(const int p_iValue)
{
    switch(p_iValue)
    {
       case MY_VALUE : /* do something */ ; break ;
       default : /* do something else */ ; break ;
    }
}

Отже, врешті-решт, розробник повинен вибрати між "швидкістю + чіткістю" та "зчепленням коду".

(Не те, що перемикач не може бути записаний як заплутаний як пекло ... Більшість перемикачів, які я зараз бачу, є з цієї "заплутаної" категорії "... Але це вже інша історія ...)

Редагувати 2008-09-21:

bk1e додав наступний коментар: " Визначення констант як перерахунків у файлі заголовка - це ще один спосіб впоратися з цим".

Звичайно, так і є.

Суть зовнішнього типу полягала в тому, щоб відокремити значення від джерела. Визначення цього значення як макросу, як простого оголошення const int, або навіть як enum має побічний ефект від включення цього значення. Таким чином, якщо дефініція, значення enum чи значення const int зміниться, знадобиться перекомпіляція. Зовнішня декларація означає, що немає необхідності перекомпілювати у разі зміни значення, але, з іншого боку, унеможливлює використання перемикача. Висновок із використання перемикача збільшить зв'язок між кодом комутатора та змінними, що використовуються як випадки . Коли це нормально, тоді використовуйте перемикач. Коли це не так, то не дивно.

.

Редагувати 2013-01-15:

Влад Лазаренко прокоментував мою відповідь, давши посилання на своє поглиблене вивчення коду складання, що генерується комутатором. Дуже радісно: http://lazarenko.me/switch/


Визначення констант як перерахунків у файлі заголовка - це ще один спосіб впоратися з цим.
bk1e

6
Перемикання не завжди швидше .

1
@Влад Лазаренко: Дякую за посилання! Це було дуже цікаве читання.
paercebal

1
Посилання @AhmedHussein user404725 мертве. На щастя, я знайшов це у машині WayBack: web.archive.org/web/20131111091431/http://lazarenko.me/2013/01/… . Дійсно, машина WayBack може бути достатнім благом.
Джек Гіффін

Велике спасибі, це дуже корисно
Ахмед Хуссейн

20

Компілятор все одно оптимізує його - перейдіть до перемикача, оскільки він найбільш читабельний.


3
Ймовірно, компілятор не торкнеться if-then-else. Насправді, gccцього точно не зроблять (для цього є вагома причина). Кланг оптимізує обидва випадки до двійкового пошуку. Наприклад, дивіться це .

7

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

ERROR_01 : // навмисне пропускання

або

(ERROR_01 == numError) ||

Пізніше більш схильна до помилок і вимагає більше введення та форматування, ніж перша.


6

Код для читабельності. Якщо ви хочете знати, що краще, скористайтеся профілером, оскільки оптимізації та компілятори різняться, а продуктивність рідко там, де люди думають, що вони є.


6

Використовуйте перемикач, це те, для чого він потрібен і що програмісти очікують.

Я хотів би поставити надмірні ярлики на корпусі - просто для того, щоб людям було комфортно, я намагався згадати, коли / які правила є для їх виходу.
Ви не хочете, щоб черговий програміст, який працював над цим, не мав зайвих роздумів про мовні деталі (це може бути ви через кілька місяців!)


4

Компілятори справді хороші в оптимізації switch. Останні gcc також добре оптимізують купу умов уif .

Я зробив кілька тестових випадків на Godbolt .

Коли case значення згруповані близько один до одного, gcc, clang та icc все досить розумні, щоб використовувати растрову карту, щоб перевірити, чи є значення одним із спеціальних.

наприклад, gcc 5.2 -O3 збирає switchдо (і ifщось дуже схоже):

errhandler_switch(errtype):  # gcc 5.2 -O3
    cmpl    $32, %edi
    ja  .L5
    movabsq $4301325442, %rax   # highest set bit is bit 32 (the 33rd bit)
    btq %rdi, %rax
    jc  .L10
.L5:
    rep ret
.L10:
    jmp fire_special_event()

Зауважте, що растрові карти - це негайні дані, тому немає жодного потенційного кешу даних, який не пропустив би доступ до нього, або таблиці переходів.

gcc 4.9.2 -O3 компілює switchв растрову карту, але робить 1U<<errNumberз mov / shift. Він компілює ifверсію до серії галузей.

errhandler_switch(errtype):  # gcc 4.9.2 -O3
    leal    -1(%rdi), %ecx
    cmpl    $31, %ecx    # cmpl $32, %edi  wouldn't have to wait an extra cycle for lea's output.
              # However, register read ports are limited on pre-SnB Intel
    ja  .L5
    movl    $1, %eax
    salq    %cl, %rax   # with -march=haswell, it will use BMI's shlx to avoid moving the shift count into ecx
    testl   $2150662721, %eax
    jne .L10
.L5:
    rep ret
.L10:
    jmp fire_special_event()

Зверніть увагу, як він віднімає 1 з errNumberleaкомбінувати цю операцію з переміщенням). Це дозволяє йому вписати растрове зображення в 32-бітовий негайний, уникаючи 64-бітового негайногоmovabsq який займає більше байтів інструкцій.

Коротка (в машинному коді) послідовність буде:

    cmpl    $32, %edi
    ja  .L5
    mov     $2150662721, %eax
    dec     %edi   # movabsq and btq is fewer instructions / fewer Intel uops, but this saves several bytes
    bt     %edi, %eax
    jc  fire_special_event
.L5:
    ret

(Невміння використовувати jc fire_special_eventвсюди, і це помилка компілятора .)

rep retвикористовується для галузевих цілей та наступних умовних гілок на користь старих AMD K8 та K10 ( передбульдозер ): Що означає `re ret`? . Без цього прогнозування галузей не працює на цих застарілих процесорах.

bt(бітовий тест) з аргументом регістру швидко. Він поєднує в собі роботу лівого зсуву a 1 на errNumberбіти і виконання atest , але все ж затримка 1 циклу і лише одна Intel взагалі. Із аргументом пам’яті це повільно через його семантику, яка занадто є CISC: з операндом пам’яті для «бітового рядка» адреса байта, що підлягає тестуванню, обчислюється на основі іншого аргументу (розділеного на 8), і isn не обмежується 1, 2, 4 або 8-байтним фрагментом, на який вказує операнд пам'яті.

З таблиць інструкцій Agner Fog інструкція зсуву змінної повільніше відбувається, ніж у btнедавнього Intel (2 Uops замість 1, і shift не робить все, що потрібно).


4

Переваги перемикача () over, якщо інший випадок:

  1. Коли є ні. Значень для одного виразу, випадок перемикання є більш гнучким у порівнянні з іншим, тому що в іншому випадку судження засноване лише на двох значеннях, тобто істинному або хибному.

  2. Значення в комутаторі визначаються користувачем, тоді як значення в іншому випадку базуються на обмеженнях.

  3. У випадку помилки, висловлювання в перемикачі можна легко перехрестити і виправити, що порівняно складно перевірити у випадку, якщо інше твердження.

  4. Корпус комутатора набагато компактніший і легкий для читання та розуміння.


2

IMO - це прекрасний приклад того, для чого було зроблено пропуск комутатора.


в c # це єдиний випадок, коли думка про падіння трапляється. Хороший аргумент саме там.
BCS

2

Якщо ваші випадки, ймовірно, залишатимуться в групі в майбутньому - якщо одному результату відповідає більше ніж один випадок - комутатор може виявитися легшим для читання та обслуговування.


2

Вони однаково добре працюють. Продуктивність приблизно така ж, як і сучасний компілятор.

Я вважаю за краще, якщо висловлювання над твердженнями випадків, оскільки вони є більш читабельними та більш гнучкими - ви можете додати інші умови, не засновані на числовій рівності, наприклад "|| max <min". Але для простого випадку, який ви розмістили тут, це насправді не має значення, просто робіть те, що вам найчитає.


2

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

Дублювання в ifстані важко для очей. Припустимо, ==був написаний один із!= ; ти помітив би? Або якщо в одному екземплярі "numError" було написано "nmuError", який щойно трапився для компіляції?

Я взагалі вважаю за краще використовувати поліморфізм замість перемикача, але без деталей контексту важко сказати.

Що стосується продуктивності, то найкраще скористатися профілером для вимірювання продуктивності вашої програми в умовах, схожих на очікувані в дикій природі. В іншому випадку ви, мабуть, оптимізуєтесь у неправильному місці та в неправильному напрямку.


2

Я погоджуюся з сумісністю рішення комутатора, але ІМО ви тут викрадаєте вимикач .
Призначення вимикача полягає в різному керуванні залежно від значення.
Якби вам довелося пояснювати свій algo в псевдо-коді, ви б використовували if, тому що, семантично, це те, що це таке: якщо what_error зробити це ...
Тож якщо ви не збираєтесь колись змінити свій код, щоб мати специфічний код для кожної помилки , Я б користувався, якби .


2
Я не згоден із тієї ж причини, що я не згоден із випадком падіння. Я читав вимикач як "У випадках 01,07,0A, 10,15,16 та 20 пожежних спеціальних подій". В інший розділ немає падіння. Це лише артефакт синтаксису C ++, де ви повторюєте ключове слово 'case' для кожного значення.
MSalters

1

Я б обрав заяву if для ясності та умовності, хоча я впевнений, що деякі не погоджуються. Зрештою, ви хочете зробити щось, за якої ifумови це правда! Мати комутатор з однією дією здається трохи ... нецікавим.


1

Я б сказав, використовуйте SWITCH. Таким чином, вам доведеться реалізувати лише різні результати. Ваші десять однакових випадків можуть використовувати за замовчуванням. Якщо потрібно змінити все, що вам потрібно, явно реалізувати ці зміни, не потрібно редагувати типово. Додавати або видаляти випадки з SWITCH також набагато простіше, ніж редагувати IF та ELSEIF.

switch(numerror){
    ERROR_20 : { fire_special_event(); } break;
    default : { null; } break;
}

Можливо, навіть перевірити свій стан (в даному випадку числовий помилок) на перелік можливостей, можливо, масив, тому ваш SWITCH навіть не використовується, якщо напевно не буде результату.


Всього близько 30 помилок. 10 вимагають спеціальної дії, тому я використовую за замовчуванням для ~ 20 помилок, які не потребують дії ...
Zing-

1

Бачачи, що у вас є лише 30 кодів помилок, кодуйте власну таблицю стрибків, тоді ви робите всі варіанти оптимізації (стрибок завжди буде найшвидшим), а не сподіваєтесь, що компілятор зробить правильно. Це також робить код дуже малим (крім статичної декларації таблиці стрибків). Це також має побічну перевагу, що за допомогою налагоджувача ви можете змінювати поведінку під час виконання, якщо вам це потрібно, просто натискаючи на дані таблиці.


Нічого собі, це здається способом перетворити просту проблему в складну. Навіщо йти на всю цю неприємність, коли компілятор зробить для вас чудову роботу. Плюс це, мабуть, обробник помилок, тому це, швидше за все, не буде настільки критичним. Перемикач - це найпростіша річ для читання та обслуговування.
MrZebra

Таблиця навряд чи складна - насправді це, мабуть, простіше, ніж перехід на код. І ця заява згадала про ефективність діяльності.
Грег Уітфілд

Це звучить як передчасна оптимізація. Поки ви зберігаєте значення перерахунків невеликими та суміжними, компілятор повинен робити це за вас. Якщо вимкнути перемикач в окрему функцію, код, який використовує його приємно і мало, як і пропонує Марк Рансом у своїй відповіді, дає таку ж перевагу з малим кодом.
Пітер Кордес

Крім того , якщо ви збираєтеся реалізувати що - або самостійно, зробити std::bitset<MAXERR> specialerror;, то if (specialerror[err]) { special_handler(); }. Це буде швидше, ніж стрибковий стіл, особливо. у незайнятому випадку.
Пітер Кордес

1

Я не впевнений у передовій практиці, але я б скористався перемикачем - а потім уловлював навмисне пропуск через "за замовчуванням"


1

Естетично я схильний до такого підходу.

unsigned int special_events[] = {
    ERROR_01,
    ERROR_07,
    ERROR_0A,
    ERROR_10,
    ERROR_15,
    ERROR_16,
    ERROR_20
 };
 int special_events_length = sizeof (special_events) / sizeof (unsigned int);

 void process_event(unsigned int numError) {
     for (int i = 0; i < special_events_length; i++) {
         if (numError == special_events[i]) {
             fire_special_event();
             break;
          }
     }
  }

Зробіть дані трохи розумнішими, щоб ми могли зробити логіку трохи тупішою.

Я розумію, це виглядає дивно. Ось натхнення (з того, як я це зробив би в Python):

special_events = [
    ERROR_01,
    ERROR_07,
    ERROR_0A,
    ERROR_10,
    ERROR_15,
    ERROR_16,
    ERROR_20,
    ]
def process_event(numError):
    if numError in special_events:
         fire_special_event()

4
Синтаксис мови дійсно впливає на те, як ми реалізуємо рішення ... => Це виглядає негарно в C і добре в Python. :)
rlerallut

Використовувати растрові карти? Якщо error_0a дорівнює 0x0a тощо, ви можете розмістити їх у вигляді бітів дуже довго. довгий довгий special_events = 1LL << 1 | 1LL << 7 | 1LL << 0xa ... Тоді використовуйте if (special_events & (1LL << numError) fire_special_event ()
папір для коней

1
Гидота. Ви перетворили операцію O (1) в гіршому випадку (якщо генеруються таблиці стрибків) в O (N) найгірший (де N - кількість оброблюваних випадків), і ви використовували breakзовнішню case(так, неповнолітню гріх, але все-таки гріх). :)
Мак

Гидота? За його словами, продуктивність та простір не є критичними. Я просто пропонував інший спосіб поглянути на проблему. Якщо ми можемо представляти проблему таким чином, коли люди менше думають, то мені зазвичай все одно, чи це означає, що комп’ютери повинні думати більше.
mbac32768

1
while (true) != while (loop)

Ймовірно, перший оптимізований компілятором, що пояснить, чому другий цикл повільніше при збільшенні кількості циклу.


Це, мабуть, є коментарем до відповіді МакАнікса. Це лише одна з проблем цієї спроби синхронізації ifпорівняно switchз умовою циклу в Java.
Пітер Кордес

1

Що стосується складання програми, я не знаю, чи є якась різниця. Але що стосується самої програми та збереження коду максимально просто, я особисто думаю, що це залежить від того, що ви хочете зробити. якщо інше, якщо в інших заявах є свої переваги, які, на мою думку, є:

дозволяють перевірити змінну на конкретні діапазони, ви можете використовувати функції (Стандартна бібліотека або Особисті) як умовні.

(приклад:

`int a;
 cout<<"enter value:\n";
 cin>>a;

 if( a > 0 && a < 5)
   {
     cout<<"a is between 0, 5\n";

   }else if(a > 5 && a < 10)

     cout<<"a is between 5,10\n";

   }else{

       "a is not an integer, or is not in range 0,10\n";

Однак якщо інше, якщо інше заяви можуть поспішати складними і безладними (незважаючи на ваші найкращі спроби). Висловлювання комутаторів, як правило, більш чіткі, чистіші та легші для читання; але може використовуватися лише для тестування на конкретні значення (приклад:

`int a;
 cout<<"enter value:\n";
 cin>>a;

 switch(a)
 {
    case 0:
    case 1:
    case 2: 
    case 3:
    case 4:
    case 5:
        cout<<"a is between 0,5 and equals: "<<a<<"\n";
        break;
    //other case statements
    default:
        cout<<"a is not between the range or is not a good value\n"
        break;

Я вважаю за краще, якщо - інакше, якщо - ще заяви, але це справді залежить від вас. Якщо ви хочете використовувати функції як умови, або ви хочете тестувати щось на діапазоні, масиві чи векторі та / або ви не проти мати справу зі складним вкладом, я рекомендую використовувати, якщо інше блокує. Якщо ви хочете перевірити окремі значення або вам потрібен чистий і легкий для читання блок, я рекомендую вам використовувати блоки корпусу switch ().


0

Я не людина, яка розповість вам про швидкість та використання пам’яті, але дивитись на стан перемикача - це пекло набагато простіше зрозуміти, ніж великий, якщо твердження (особливо 2-3 місяці вниз)


0

Я знаю його старе, але

public class SwitchTest {
static final int max = 100000;

public static void main(String[] args) {

int counter1 = 0;
long start1 = 0l;
long total1 = 0l;

int counter2 = 0;
long start2 = 0l;
long total2 = 0l;
boolean loop = true;

start1 = System.currentTimeMillis();
while (true) {
  if (counter1 == max) {
    break;
  } else {
    counter1++;
  }
}
total1 = System.currentTimeMillis() - start1;

start2 = System.currentTimeMillis();
while (loop) {
  switch (counter2) {
    case max:
      loop = false;
      break;
    default:
      counter2++;
  }
}
total2 = System.currentTimeMillis() - start2;

System.out.println("While if/else: " + total1 + "ms");
System.out.println("Switch: " + total2 + "ms");
System.out.println("Max Loops: " + max);

System.exit(0);
}
}

Варіація зміни циклу сильно змінюється:

Хоча якщо / ще: 5ms перемикання: 1ms Максимальна кількість циклів: 100000

Хоча якщо / ще: 5ms Перемикач: 3ms Максимальна кількість циклів: 1000000

Хоча якщо / ще: 5ms Перемикач: 14ms Максимальна кількість циклів: 10000000

Хоча якщо / ще: 5ms Перемикач: 149ms Максимальна кількість циклів: 100000000

(додайте ще заяви, якщо хочете)


3
Хороша думка, але вибачте, чувак, ти не на тій мові. Різноманітність мови сильно змінюється;)
Габріель Шрайбер

2
if(max) breakЦикл працює в постійна час незалежно від числа петель? Здається, що компілятор JIT досить розумний, щоб оптимізувати цикл counter2=max. І, можливо, це повільніше, ніж перемикання, якщо перший дзвінок currentTimeMillisмає більше накладних витрат, адже ще не все компільовано JIT? Розміщення циклів в іншому порядку, ймовірно, дасть різні результати.
Пітер Кордес
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.