Когда для оптимизации памяти против скорость работы метода?

Недавно я беседовал на Amazon. Во время сеанса кодирования, интервьюер спрашивает, почему я объявил переменную в метод. Я объяснил свой процесс и он бросил мне вызов, чтобы решить ту же проблему с меньшим количеством переменных. Например (это было'т из интервью), я начал с метод то улучшенная ее метод B, убрав инт ы. Он был доволен и сказал, что это позволит сократить использование памяти Этим методом.

Я понимаю логику, стоящую за этим, но мой вопрос:

Когда целесообразно использовать метод A и метод B, и наоборот?

Вы можете видеть этот метод будет иметь более высокое использование памяти, с инт ыобъявлена, но это только для выполнения одного расчета, т. е.А + Б. С другой стороны, *метод B* имеет низкое использование памяти, но должен выполнить два расчета, т. е.А + Б` дважды. Когда я использую одну технику над другими? Или, является одним из методов всегда предпочтительнее другого? Что нужно учитывать при оценке двух методов?

Метод:

в

private bool IsSumInRange(int a, int b)
{
    int s = a + b;

    if (s > 1000 || s < -1000) return false;
    else return true;
}

Метод Б:

private bool IsSumInRange(int a, int b)
{
    if (a + b > 1000 || a + b < -1000) return false;
    else return true;
}
Комментарии к вопросу (27)
Решение

Вместо того чтобы размышлять о том, что может или не может случиться, пусть's просто посмотрим, Да? Я'll должны использовать C++, так как я Дон'т иметь компилятор C# удобный (хотя [см. пример на языке C#] [КС] от VisualMelon), но я'уверен, что те же принципы применяются независимо от. Мы'МР включают две альтернативы, с которой вы столкнулись в интервью. Мы'МР также есть версия, которая использует АБС, как полагают некоторые ответы. в

#include 

bool IsSumInRangeWithVar(int a, int b)
{
    int s = a + b;

    if (s > 1000 || s < -1000) return false;
    else return true;
}

bool IsSumInRangeWithoutVar(int a, int b)
{
    if (a + b > 1000 || a + b < -1000) return false;
    else return true;
}

bool IsSumInRangeSuperOptimized(int a, int b) {
    return (abs(a + b) < 1000);
}

Теперь его скомпилировать без оптимизации: г++ -С-О тест.о test.cpp Теперь мы можем видеть именно то, что это порождает: `objdump -d проверит.о'

0000000000000000 :
   0:   55                      push   %rbp              # begin a call frame
   1:   48 89 e5                mov    %rsp,%rbp
   4:   89 7d ec                mov    %edi,-0x14(%rbp)  # save first argument (a) on stack
   7:   89 75 e8                mov    %esi,-0x18(%rbp)  # save b on stack
   a:   8b 55 ec                mov    -0x14(%rbp),%edx  # load a and b into edx
   d:   8b 45 e8                mov    -0x18(%rbp),%eax  # load b into eax
  10:   01 d0                   add    %edx,%eax         # add a and b
  12:   89 45 fc                mov    %eax,-0x4(%rbp)   # save result as s on stack
  15:   81 7d fc e8 03 00 00    cmpl   $0x3e8,-0x4(%rbp) # compare s to 1000
  1c:   7f 09                   jg     27                # jump to 27 if it's greater
  1e:   81 7d fc 18 fc ff ff    cmpl   $0xfffffc18,-0x4(%rbp) # compare s to -1000
  25:   7d 07                   jge    2e                # jump to 2e if it's greater or equal
  27:   b8 00 00 00 00          mov    $0x0,%eax         # put 0 (false) in eax, which will be the return value
  2c:   eb 05                   jmp    33 
  2e:   b8 01 00 00 00          mov    $0x1,%eax         # put 1 (true) in eax
  33:   5d                      pop    %rbp
  34:   c3                      retq

0000000000000035 :
  35:   55                      push   %rbp
  36:   48 89 e5                mov    %rsp,%rbp
  39:   89 7d fc                mov    %edi,-0x4(%rbp)
  3c:   89 75 f8                mov    %esi,-0x8(%rbp)
  3f:   8b 55 fc                mov    -0x4(%rbp),%edx
  42:   8b 45 f8                mov    -0x8(%rbp),%eax  # same as before
  45:   01 d0                   add    %edx,%eax
  # note: unlike other implementation, result is not saved
  47:   3d e8 03 00 00          cmp    $0x3e8,%eax      # compare to 1000
  4c:   7f 0f                   jg     5d 
  4e:   8b 55 fc                mov    -0x4(%rbp),%edx  # since s wasn't saved, load a and b from the stack again
  51:   8b 45 f8                mov    -0x8(%rbp),%eax
  54:   01 d0                   add    %edx,%eax
  56:   3d 18 fc ff ff          cmp    $0xfffffc18,%eax # compare to -1000
  5b:   7d 07                   jge    64 
  5d:   b8 00 00 00 00          mov    $0x0,%eax
  62:   eb 05                   jmp    69 
  64:   b8 01 00 00 00          mov    $0x1,%eax
  69:   5d                      pop    %rbp
  6a:   c3                      retq

000000000000006b :
  6b:   55                      push   %rbp
  6c:   48 89 e5                mov    %rsp,%rbp
  6f:   89 7d fc                mov    %edi,-0x4(%rbp)
  72:   89 75 f8                mov    %esi,-0x8(%rbp)
  75:   8b 55 fc                mov    -0x4(%rbp),%edx
  78:   8b 45 f8                mov    -0x8(%rbp),%eax
  7b:   01 d0                   add    %edx,%eax
  7d:   3d 18 fc ff ff          cmp    $0xfffffc18,%eax
  82:   7c 16                   jl     9a 
  84:   8b 55 fc                mov    -0x4(%rbp),%edx
  87:   8b 45 f8                mov    -0x8(%rbp),%eax
  8a:   01 d0                   add    %edx,%eax
  8c:   3d e8 03 00 00          cmp    $0x3e8,%eax
  91:   7f 07                   jg     9a 
  93:   b8 01 00 00 00          mov    $0x1,%eax
  98:   eb 05                   jmp    9f 
  9a:   b8 00 00 00 00          mov    $0x0,%eax
  9f:   5d                      pop    %rbp
  a0:   c3                      retq

Мы можем видеть из стека адресов (например, - признаки 0x4 " в "мову %Эди,-признаки 0x4(%РБП) против -0x14" в " мову %Эди,-0x14(%РБП)), что IsSumInRangeWithVar() используется 16 лишних байт на стеке. Потому что IsSumInRangeWithoutVar()выделяет нет места в стеке для хранения промежуточных значенийЫон должен пересчитать ее, в результате чего это станет 2 инструкция больше. Забавно, IsSumInRangeSuperOptimized() выглядит как IsSumInRangeWithoutVar (), за исключением сравнивает первых -1000 и 1000 второй. Теперь давайте&#39;ы составить только самое основное оптимизация:г++ -О1 -с-о тест.о test.cpp`. Результат:

0000000000000000 :
   0:   8d 84 37 e8 03 00 00    lea    0x3e8(%rdi,%rsi,1),%eax
   7:   3d d0 07 00 00          cmp    $0x7d0,%eax
   c:   0f 96 c0                setbe  %al
   f:   c3                      retq

0000000000000010 :
  10:   8d 84 37 e8 03 00 00    lea    0x3e8(%rdi,%rsi,1),%eax
  17:   3d d0 07 00 00          cmp    $0x7d0,%eax
  1c:   0f 96 c0                setbe  %al
  1f:   c3                      retq

0000000000000020 :
  20:   8d 84 37 e8 03 00 00    lea    0x3e8(%rdi,%rsi,1),%eax
  27:   3d d0 07 00 00          cmp    $0x7d0,%eax
  2c:   0f 96 c0                setbe  %al
  2f:   c3                      retq

Ты только посмотри: каждый вариант identical. Компилятор умеет делать что-то умное: АБС(а + в) <= 1000эквивалентноа + б + 1000 <= 2000учитываяsetbeделает сравнение без знака, поэтому отрицательное число становится очень большим положительным числом. ВЛеа` инструкция на самом деле могут выполнять все эти дополнения в одну инструкцию, и устранить все условные переходы. Чтобы ответить на ваш вопрос, almost always, что нужно оптимизировать по памяти или скорости, но readability. Чтение кода гораздо сложнее, чем ее написание и чтение кода, что'ы были подогнаны, чтобы "оптимизировать" это гораздо труднее, чем чтение кода, что'было написано для ясности. Чаще чем не, эти-то "оптимизации" имеют ничтожно мала, или как в данном случае exactly zero фактическое влияние на производительность.

последующий вопрос, какие изменения, когда этот код на интерпретируемом языке вместо компиляции? Тогда оптимизация дело или не иметь тот же результат? Позвольте'ы измерения! Я'вэ переписал примеры на Python:


def IsSumInRangeWithVar(a, b):
    s = a + b
    if s > 1000 or s < -1000:
        return False
    else:
        return True

def IsSumInRangeWithoutVar(a, b):
    if a + b > 1000 or a + b < -1000:
        return False
    else:
        return True

def IsSumInRangeSuperOptimized(a, b):
    return abs(a + b) 
Комментарии (22)

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

когда для оптимизации памяти скорость работы метода?

Есть две вещи, которые вы должны установить:

  • Что ограничивает вашу заявку?
  • Где я могу вернуть большую часть этого ресурса?

Для того, чтобы ответить на первый вопрос, вы должны знать, что требования к производительности для вашего приложения. Если нет требований, то нет смысла оптимизировать так или иначе. Требования по производительности могут помочь вам добраться до места "и достаточно хорошо и".

Метод, который вы предоставили по себе не'т вызвать какие-либо проблемы с производительностью на собственного, но, возможно, в цикле и обрабатывать большие объемы данных, вы должны начать думать немного иначе о том, как вы приближаетесь проблема.

Обнаруживая, что ограничивает применение

Начните глядя на поведение вашего приложения с помощью системного монитора. Отслеживать использование процессора, диска, сети и памяти, пока он's работает. Один или несколько элементов будет превышен, а все остальное-в меру использовать ... если вы попали в идеальный баланс, но этого почти никогда не происходит).

Когда вам нужно смотреть глубже, как правило, вы будете использовать profiler. Есть memory profilers и process profilers, и они измеряют разные вещи. Акт профилирования имеет значительное влияние на производительность, но вы не инструментирование кода, чтобы выяснить, что'ы не так.

Позвольте'говорят, что вы видите вашего процессора и диска достигла максимума. Вы бы сначала проверять на "горячих точках" или код, который либо называется чаще, чем в остальных и занимает значительно больше процент обработки.

Если вы можете'т найти любые горячие точки, тогда вам будет начать поиски в памяти. Возможно, вы создаете больше объектов, чем необходимо, и ваш сборка мусора работает сверхурочно.

Восстановление производительности

Критически мыслить. Следующий список изменений в порядок сколько возврата инвестиций вы'll получить:

  • Архитектура: искать пропускные пункты связи
  • Алгоритм: способ обработки данных может потребоваться изменить
  • Горячие точки: минимизировать, как часто вы звоните в горячую точку могут дать большой бонус
  • Микро-оптимизаций: это's не часто, но иногда вы действительно должны думать о незначительных настроек (как в примере вы указали), особенно если это горячая точка в коде.

В таких ситуациях нужно применять научный метод. Придумать гипотезу, внести изменения, и проверить его. Если вы встречаете ваших целей производительности, вы'повторно сделано. Если нет, переходим к следующему в списке.


Отвечая на вопрос жирным шрифтом:

когда целесообразно использовать метод A и метод B, и наоборот?

Честно, это последний шаг в попытке решить проблему производительности или проблемы с памятью. Влияние метод A и метод B будет очень разным в зависимости от языка и платформа (в некоторых случаях).

Просто о каких-либо compiled language с мало-мальски приличный оптимизатор будет генерировать подобный код с любой из этих структур. Однако эти предположения не'т должен оставаться верным в фирменной и игрушки языков, что Дон'Т есть оптимизатор.

Точно, у которых будет лучшее воздействие зависит от того, сумма - это переменная стека или кучи переменных. Это выбор языка реализации. В C, C++ и Java, например, количество примитивов, как инт являются переменными стека по умолчанию. Ваш код имеет большее влияние памяти путем присвоения переменной стека, чем вы бы с полностью встроен код.

Других оптимизаций, которые вы можете найти в библиотеках с (особенно старые), где вы можете решить между копированием 2 мерный массив первый или во-первых, это зависит от платформы оптимизации. Это требует некоторых знаний о том, как чипсет вы ориентируетесь лучше оптимизирует доступ к памяти. Есть тонкие различия между архитектурами.

Суть в том, что оптимизация-это сочетание искусства и науки. Это требует критического мышления, а также степень гибкости в том, как подходить к проблеме. Искать большие вещи, прежде чем упрекать по мелочам.

Комментарии (8)

и"это уменьшило бы память" - ЭМ, нет. Даже если это окажется правдой (что, для любого приличного компилятора нет), то разница скорее всего будет незначительным для любой реальной ситуации в мире.

Однако, я бы рекомендовал использовать метод* (метод с небольшим изменением):


private bool IsSumInRange(int a, int b)
{
    int sum = a + b;

    if (sum > 1000 || sum < -1000) return false;
    else return true;
    // (yes, the former statement could be cleaned up to
    // return abs(sum)
Комментарии (10)

Вы можете сделать лучше, чем эти с

return (abs(a + b) > 1000);

Большинство процессоров (и, следовательно, компиляторы) может сделать АБС() в одной операции. Вы не только меньшую сумму, но и меньшее количество сравнений, которые, как правило, более в вычислительном отношении дорого. Он также удаляет ветвления, что гораздо хуже для большинства процессоров, так как она не конвейеризация возможным.

Интервьюер, как и другие ответы уже сказал, Жизнь растений и не проводит техническое собеседование.

Что сказал, на его вопрос действителен. И ответа на вопрос: когда вы оптимизируете и как, это когда вы'вэ доказал это's необходимый, и вы'вэ профилированного это, чтобы доказать, какие именно части нужно. Кнут лихо заявил, что преждевременная оптимизация-корень всех зол, потому что он's слишком легко, чтобы попытаться золочение неважных разделов, или внести изменения (например, ваш интервьюер'ов), которые не имеют никакого эффекта, пока хватает мест, которые действительно нуждаются в этом. Пока вы've получили веские доказательства его's действительно необходимо, чистота кода-это более важная цель.

Редактировать FabioTurati правильно указывает, что это противоречит логике смысла оригинала, (моя ошибка!), и что это иллюстрирует дальнейшее влияние от кнута'ы цитату, где мы рискуем сломать код, пока мы'вновь пытается оптимизировать его.

Комментарии (10)

когда целесообразно использовать метод A и метод B, и наоборот?

Оборудование дешево; программисты стоят дорого. Так что стоимость времени, что вы зря на этот вопрос, наверное, гораздо хуже, чем любой ответ.

Несмотря на это, большинство современных компиляторов бы найти способ оптимизировать локальную переменную в регистр (вместо того, чтобы выделить пространство стека), поэтому эти методы, вероятно, идентичны с точки зрения исполняемого кода. По этой причине большинство разработчиков выбрали бы тот вариант, который взаимодействует наиболее четко намерение (см. писать действительно очевидный код (ОКР)). На мой взгляд, это было бы методу А.

С другой стороны, если это чисто академическое упражнение, вы можете иметь лучшее из обоих миров с метод c:


private bool IsSumInRange(int a, int b)
{
    a += b;
    return (a >= -1000 && a 
Комментарии (12)

Я бы оптимизировать для удобства чтения. Метод Х:


private bool IsSumInRange(int number1, int number2)
{
    return IsValueInRange(number1+number2, -1000, 1000);
}

private bool IsValueInRange(int Value, int Lowerbound, int Upperbound)
{
    return  (Value >= Lowerbound && Value 
Комментарии (8)

Короче, я не'т думаю, что вопрос имеет актуальность в текущих вычислений, но с исторической точки зрения это'Очень интересный мысленный эксперимент.

Ваш интервьюер, вероятно, поклонник Мифический человеко месяц. В книге, Фред Брукс дает понять, что программисты, как правило, нужны две версии ключевых функций в свой набор: память-оптимизированная версия и процессор-оптимизированные версии. Фред основываясь на своем опыте ведущих развитие системы IBM/360 операционная система, где машины могут иметь до 8 килобайт оперативной памяти. В таких машинах, требуемый объем памяти для локальных переменных в функциях может быть важно, особенно если компилятор не оптимизировать их (или если код был написан на языке ассемблера напрямую).

В нынешнюю эпоху, я думаю, вы были бы в затруднении, чтобы найти систему, в которой наличие или отсутствие локальной переменной в методе внесет заметной разницы. Для переменной к вопросу, метод должен быть рекурсивный с глубокой рекурсии ожидается. Даже тогда, это'вероятность того, что глубина стека будет превышен вызывает исключение переполнения стека перед самой переменной вызвало проблему. Единственный реальный сценарий, где это может быть проблема с очень большой, массивы в стеке в рекурсивный метод. Но это также маловероятно, как я думаю, что большинство разработчиков будет думать дважды о ненужных копий больших массивов.

Комментарии (0)

После выполнения задания с = А + Б; переменные a и B не используется. Поэтому, нет памяти используется для S Если вы не используете полностью поврежден мозг компилятора; память, которая была так или иначе использована для A и B используется повторно.

Но оптимизации эта функция полнейший бред. Если вы можете сэкономить пространство, было бы может быть 8 байт, а функция выполняется (который восстанавливается, когда функция возвращает), поэтому абсолютно бессмысленно. Если вы могли бы сэкономить время, это будет один число наносекунд. Оптимизация это пустая трата времени.

Комментарии (0)

Локальные переменные тип значения размещаются в стеке или (что более вероятно для таких маленьких кусочков кода) использовать регистры в процессоре и не вижу каких-либо рам. В любом случае они недолговечны и не о чем беспокоиться. Вы начинаете рассматривать использование памяти, когда вы нуждаетесь в буфер или очередь элементов данных в коллекции, которые являются оба потенциально большие и долго живут.

Тогда это зависит от того, что вы заботитесь о Больше всего для вашего приложения. Скорость обработки? Время отклика? След памяти? Ремонтопригодность? Последовательность в дизайне? Все зависит от вас.

Комментарии (2)

Как и другие ответы уже сказал, нужно думать, что вы'вэ оптимизации для.

В этом примере, я подозреваю, что любой приличный компилятор будет генерировать эквивалентный код для обоих методов, поэтому решение никак не повлияет на время выполнения or памяти!

Что это -- как раз это влияет на читаемость кода.  (код для людей, чтобы читать, а не только компьютеры.)  там's не слишком большая разница между двумя примерами; при прочих равных условиях, я считаю, краткость достоинство, поэтому я'д, наверное, выберет метод Б.  но все остальные вещи редко бывают равными, и в более сложном реальном мире дело, это может иметь большой эффект.

Вещи, чтобы рассмотреть:

  • Делает промежуточных выражение имеет каких-либо побочных эффектов?  если он называет всякого нечистого функций или обновления каких-либо переменных, то, конечно, дублирование было бы вопрос о правильности, а не просто стиль.
  • Насколько сложной является промежуточным выражение?  если он делает много расчетов и/или вызовы функций, то компилятор не сможет оптимизировать его, и таким образом это будет влиять на производительность.  (хотя, как кнут [сказал][1], “Мы должны забывать о небольшой эффективности, скажем, около 97% времени”.)
  • Делает промежуточной переменной у любого meaning?  это может быть дано имя, которое помогает объяснить, что'что происходит?  короткое, но информативное имя могло бы лучше объяснить код, а бессмысленным-это просто визуальный шум.
  • Сколько времени занимает промежуточное выражение?  если долго, то дублировать это может сделать код дольше и труднее читать (особенно если она заставляет разрыв строки); если нет, то дублирование может быть короче во всем.

[1]: я https://en.wikiquote.org/wiki/Donald_Knuth#Computer_Programming_as_an_Art_(1974) &; сказал"

Комментарии (0)

Как и многие ответы подчеркивали, пытаясь настроить эту функцию с современными компиляторами выиграл'т делать какие-либо разница. Оптимизатор, можно с большой вероятностью выяснить, лучшее решение (проголосовать в ответ, что показал ассемблерный код, чтобы доказать это!). Вы заявили, что код в интервью не совсем тот код, который вы попросили сравнить, поэтому, возможно, реальный пример делает немного больше смысла.

Но позвольте's по-другому взглянуть на этот вопрос: это интервью вопрос. Таким образом, реальный вопрос, как вы должны ответить на него, предполагая, что вы хотите попробовать и получить работу?

Позвольте's также предполагают, что собеседник знает, о чем они говорят, и они просто пытаются посмотреть, что вы знаете.

Я хотел бы отметить, что игнорирование оптимизатор, первый может создать временную переменную на стеке, а второй не't, но будет выполнять два расчета. Поэтому первый использует больше памяти, но быстрее.

Можно отметить, что в любом случае, расчет может потребоваться временная переменная для хранения результата (так, чтобы быть по сравнению), так ли вы имя переменной или не может, не имеет никакого значения.

Затем я хотел бы отметить, что в реальности код будет оптимизирован и, скорее всего, эквивалентный машинный код будет сгенерирован, так как все переменные являются локальными. Однако, это никак зависеть от того, какой компилятор вы используете (это было не так давно, что я мог бы сделать полезное улучшение производительности при объявлении локальной переменной, как "окончательной" в языке Java).

Можно отметить, что стек в любом случае живет в своей собственной страницы памяти, так что, если ваш лишний переменной вызвало стек переполнять страницы, он выиграл'т в реальности выделить больше памяти. Если это произойдет переполнения, он будет хоть всю новую страницу.

Я хотел бы отметить, что более реалистичным примером может быть выбор, использовать ли кэш для хранения результатов многочисленных расчетов или нет, и это подняло бы вопрос о памяти процессора против.

Все это показывает, что вы знаете, о чем вы говорите.

Я бы оставил его до конца, чтобы сказать, что было бы лучше, чтобы вместо этого сосредоточиться на readabilty. Хотя это и верно в данном случае, в контексте интервью это может быть interpretted как "Я не'т знаю насчет производительности, но мой код читается как Джанет и Джона история".

То, что вы должны сделать, это не пускать в обычный мягкий заявлениями о том, как оптимизация кода не надо, Дон'т оптимизировать, пока вы не профилировали код (это просто означает, что вы можете'т вижу плохой код для себя), затраты на оборудование меньше, чем программистов, и, пожалуйста, пожалуйста, Дон'т цитата кнута "и преждевременной бла-бла ..." по.

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

В частности, с такими организациями, как Amazon, часть кода имеет огромное кредитное плечо. Фрагмент кода может быть развернут на тысячи серверов и миллионы устройств и можно назвать миллиарды раз в день каждый день в году. Причин может быть тысячи подобных фрагментов. Разница между плохой алгоритм и хорошим можно быть в тысячу. Цифры и несколько все это: это делает разницу. Потенциальные расходы на организацию неработающих код может быть весьма значительным или даже смертельным, если системе не хватает мощности.

Furthmore, многие из этих организаций работают в условиях конкуренции. Поэтому вы не можете просто сказать своим клиентам возможность купить больший компьютер, если ваш конкурент'программное обеспечение уже работает на оборудовании, которое у них есть или если программное обеспечение работает на мобильный телефон и он может'т быть повышен. Некоторые приложения, в частности критическое для производительности (игры и мобильные приложения приходят на ум) и может жить или умереть по своей оперативности и скорости.

У меня лично за два десятилетия работал на многих проектах, где системы не были использованы из-за проблем с производительностью, и я был призван в оптимизации этих систем и во всех случаях она была из-за плохой код, написанный программистами, которые я'т понять влияние, что они пишут. Furthmore, это не один кусок кода, это всегда и везде. Когда я обращаюсь, это способ поздно, чтобы начать думать о производительности: повреждение было сделано.

Понимание производительности кода-это хорошие навыки, точно так же, как понимание корректности кода и стиля кода. Он выходит из практики. Сбои производительность может быть так плохо, как функциональные сбои. Если система не'т работу, он не'т работу. Не'т важно, почему. Аналогично, производительность и функциональные возможности, которые не используются как плохо.

Так что, если вас спросят о производительности, я бы рекомендовал попробовать и продемонстрировать как можно больше знаний. Если вопрос кажется плохой, вежливо указать, почему вы думаете, что это не будет проблемой в этом случае. Дон'т цитата кнута.

Комментарии (0)

Вы должны сначала оптимизировать на правильность.

Ваша функция не выполняется для значений входного сигнала, близких к Инт.Максвеллову:

int a = int.MaxValue - 200;
int b = int.MaxValue - 200;
bool inRange = test.IsSumInRangeA(a, b);

Это возвращает true, потому что сумма переполняется до -400. Функция также не't работа для = инт.Параметр minvalue + 200. (неправильно складывает, чтобы "400" - а)

Мы выиграли'т знаю, что интервьюер ищет, если он или она вмешивается, но на"переполнение реальной и".

В ситуации интервью, задать вопросы, чтобы прояснить масштаб проблемы: что есть допустимое максимальное и минимальное значения входного сигнала? Если у вас есть эти, вы можете бросить исключение, если абонент отправляет значения за пределами диапазона. Или (в C#), вы можете использовать проверенный {раздел}, который будет бросать исключение на переполнении. Да, это's больше работы и сложным, но иногда это's то, что он принимает.

Комментарии (3)

Твой вопрос должен был звучать: "и мне нужно, чтобы оптимизировать это все?&и". Версии A и B отличаются на одну важную деталь, что делает предпочтительным, но это не имеет отношения к оптимизации: вы не повторите код. Собственно, что "оптимизации" это называется устранение общих подвыражений, что почти каждый компилятор делает. Некоторые делают это базовая оптимизация даже при оптимизации выключены. Так что это'т действительно оптимизация (сгенерированный код почти наверняка будет точно таким же в любом случае). Но если он _isn'быть, с оптимизацией, то почему это выгоднее? Ладно, вы не'т повторить код, который заботится! Ну, во-первых, у вас нет риска в accidentially получать половину условного неправильное положение. Но что еще более важно, кто-то из читающих этот код может Грок сразу то, что вы'вновь пытается сделать, а не если((((ВТФ||это||это||longexpression)))) опыт. То, что читатель получает, чтобы увидеть, если(один || Другие), который является хорошей вещью. Не редко, у меня бывает так, что вы, что другой человек, читая свой собственный код через три года и думать "и ВТФ это значит?&и". В этом случае он's всегда полезно, если ваш код сразу же сообщает, что умысел был. С общих подвыражений был назван правильно, что'ы в случае. Также, если в любое время в будущем, вы решите, что, например, нужно менять А+B до А-Б, вы должны изменить одном месте, а не два. И там's нет риска (снова) становится второй не так случайно. О ваш фактический вопрос, что вы должны оптимизировать, в первую очередь код должен быть correct. Это абсолютно самая важная вещь. Код, что это'т исправить плохой код, тем более, если несмотря на то, что неправильное ее "работает" ну, или, по крайней мере, это looks like он отлично работает. После этого код должен быть читаемым (читаемый кем-то незнаком с ним). Что касается оптимизации... определенно стоит'т сознательно пишу анти-оптимизированный код, и, конечно, я'м не говорю, что вы должны'т тратить мысли на дизайн прежде чем вы начнете (например, выбор правильного алгоритма для задачи, не наименее эффективным). Но для большинства приложений, большую часть времени, на выполнение которых вы получаете после выполнения правильный, читабельный код, используя разумный алгоритм через оптимизирующий компилятор-это просто отлично, там'не нужно беспокоиться. Если это'т делу, т. е. если приложение'спектакль действительно не'т отвечать требованиям, и только then, вы должны беспокоиться о таких оптимизаций, как вы пытались. Желательно, правда, вы бы пересмотреть верхнего уровня алгоритма. Если вы вызываете функцию в 500 раз вместо 50000 раз из-за лучшего алгоритма, это имеет большее влияние, чем спасение трех тактов на микро-оптимизации. Если вы don't в ларьке на несколько сотен циклов в оперативной памяти все время, это имеет большее влияние, чем несколько дешевых расчеты дополнительные, и т. д. и т. п. Оптимизация-это сложный вопрос (можно написать целые книги о том, что и вам до конца), и тратить время на слепо optimizting определенном месте (даже не зная, что'ы вообще узкое место!) обычно потраченное время. Без профилирования, оптимизации очень трудно получить права. Но как правило, когда вы'вновь вслепую и просто нуждаетесь/хотите сделать something, или в качестве общей стратегии по умолчанию, я бы предложил оптимизировать ПО quot&; Память". Оптимизация "Память" (в частности, пространственная локальность доступа и узоры) обычно дает пользу, потому что в отличие от давным-давно, когда все было на "такая же" в наше время доступа к оперативной памяти является одним из самых дорогих вещей (короткое чтение из диска!) что можно в принципе сделать. В то время как АЛУ, с другой стороны, это дешево и быстрее получать каждую неделю. Пропускная способность памяти и латентность не't улучшить почти так же быстро. Хороший район и хорошие модели доступа можно легко сделать 5х разница (20х в крайности, contrieved примеры) во время выполнения по сравнению с плохим моделей доступа в данных тяжелых приложений. Быть хорошим для своих схронов, и вы будете счастливым человеком. Чтобы положить предыдущем пункте, в перспективе, считают, что различные вещи, которые вы можете сделать бесплатно. Выполняя что-то вроде А+Б принимает (если не оптимизированные) один или два цикла, но процессор могут обычно начинают несколько инструкций за один цикл, а может трубопровод non-зависимые инструкции, чтобы более реально это стоит всего что-то около половины цикла или меньше. В идеале, если компилятор хорош в планировании, и в зависимости от ситуации, это может стоить ноль. Выборки данных ("Память") стоит вам либо 4-5 циклов, если вы'вновь повезло, и он's в Л1, и около 15 циклов, если вам не так повезло (Л2 бить). Если данные не'т в кэше на все, это займет несколько сотен циклов. Если ваш бессистемный узор доступа превышает ТЛБ'возможности S (это легко сделать с только ~50 записей), добавить еще несколько сотен циклов. Если ваш бессистемный узор открыть на самом деле вызывает ошибку страницы, это будет стоить вам несколько десятков тысяч циклов в лучшем случае, а в худшем миллионов. Сейчас думаю об этом, что'ы, что вы хотите, чтобы избежать наиболее остро?

Комментарии (0)

когда для оптимизации памяти скорость работы метода?

После того, как функциональность право первый. Затем selectivity заниматься микро-оптимизациями.


Как интервью вопрос по оптимизации, кода не спровоцировать обычная дискуссия, но не попадает в цель высшего уровня код функционально правильное?

C++ и C и другие связи инт переполнение как проблема с А + Б. Это не хорошо определены и C называет его undefined behavior. Это не указано, чтобы "обернуть" и хотя это общее поведение.

bool IsSumInRange(int a, int b) {
    int s = a + b;  // Overflow possible
    if (s > 1000 || s < -1000) return false;
    else return true;
}

Такая функция называется IsSumInRange() можно было бы ожидать, чтобы быть четко определены и правильно выполнять для всех значений типа int в А,Б. Сырым а + б - нет. Решение c можно использовать:

#define N 1000
bool IsSumInRange_FullRange(int a, int b) {
  if (a >= 0) {
    if (b > INT_MAX - a) return false;
  } else {
    if (b < INT_MIN - a) return false;
  }
  int sum = a + b;
  if (sum > N || sum < -N) return false;
  else return true;
}

Приведенный выше код может быть оптимизирован с помощью более широкого целого типа, чем инт, если таковая имеется, а ниже или распространяя сумма > П,сумму в < -Н-тестов в рамках `Если (а >= 0) логика. Но такая оптимизация не может по-настоящему руководить, чтобы "быстрее" и излучаемый код приведенный умный компилятор и не стоит лишний обслуживанию лукавите.

  long long sum a;
  sum += b;

Даже с помощью АБС(сумма)склонен к проблемам, когдасумма == INT_MIN`.

Комментарии (0)

Какие компиляторы мы говорим, и что-то вроде "Память"? Потому что в вашем примере, предполагая, что разумный оптимизатор, выражение a+b и должен вообще быть сохранен в регистре (в виде памяти), прежде чем приступать к такой арифметике.

Так что если мы're говоря о тупой компилятор, который обнаруживает а+в два раза, это'ы собирается выделить дополнительные регистры (память) в свой второй пример, потому что ваш первый пример может быть просто магазин, это выражение еще в одном регистре отображается в локальной переменной, но мы're говоря о очень глупо компиляторы на данный момент... если вы'работаем с другим типом глупый компилятор, который стек разливов каждой переменной повсюду, и в этом случае может быть первая вызовет больше горя для оптимизации, чем второе*.

я все еще хочу, чтобы поцарапать, что и второй, скорее всего, будет использовать больше памяти с тупой компилятор, даже если это'ы склонны к стек разливов, потому что это может в конечном итоге выделение трех регистров а+б разлив A и B больше. Если мы'заново говорить самый примитивный оптимизатор захвата А+Б В s, вероятно, "Помоги", он использует меньше регистров/стека разливов.

Все это крайне спекулятивный, а глупые способы отсутствуют измерения/разборке и даже в худшем сценарии, это не "Память и представление" в случае (потому что даже среди худших оптимизаторов, я думаю, мы'повторно не говорим о чем угодно, но временную память, как стек/регистры), это'ы чисто и "производительность" в случае, если в лучшем случае, а у любого разумного оптимизатора два эквивалентны, и если один не использует разумный оптимизатор, почему зацикливается оптимизация настолько микроскопический характер и особенно отсутствующих измерений? Что's, как инструкция выбора/сборки-уровень распределения регистров фокус, который я никогда не ожидал, что кто хочет оставаться продуктивным при использовании, скажем, переводчика, которые распространяются стек все.

когда для оптимизации памяти скорость работы метода?

Как на этот вопрос, если я могу решить ее в более широком смысле, часто я Дон'т найти две диаметрально противоположные. Особенно, если ваши модели доступа являются последовательными, и учитывая скорость кэша процессора, часто уменьшение количества байтов, последовательно нетривиальные входов переводит (до определенного момента), чтобы пахать через эти данные быстрее. Конечно, есть критические точки, где, если данных гораздо меньше в обмен на гораздо более инструкции, это может быть быстрее, чтобы процесс последовательно в большей форме в обмен на меньшее количество инструкций.

Но я'вэ нашел многие разработчики склонны недооценивать, сколько сокращение использования памяти в подобных случаях можно перевести на пропорциональное сокращение времени, затраченного на обработку. Это's очень по-человечески понятный, чтобы перевести затраты на выполнение инструкций, а не доступ к памяти до момента достижения для большой Луц в некоторых тщетных попытках ускорить некоторые небольшие расчеты, только чтобы найти производительность деградирует с дополнительным доступом к памяти.

Для последовательного доступа случаях через какой-то огромный массив (не говорю локальных скалярных переменных, как в вашем примере), я иду правилом, что меньше памяти для последовательного пашут приводит к большей производительности, особенно, когда результирующий код-это проще, чем иначе пока он не'т, пока мои измерения и профилирования убеждать меня в обратном, и это важно, таким же образом я полагаю, что последовательное чтение небольших двоичный файл на диске будет быстрее пахать через не больше одного (даже если меньше требует более какие-то инструкции), пока что предположение показано, что перестают действовать в моих измерений.

Комментарии (0)