Я объяснил своим студентам, что тестирование на равных не является надежным для переменных с плавающей точкой, но подходит для целых чисел. В учебнике, который я использую, сказано, что его легче читать> и <чем> = и <=. Я согласен в некоторой степени, но в цикле For? Разве не понятнее, чтобы цикл указывал начальные и конечные значения?
Я что-то упустил, о чем автор учебника прав?
Другой пример - тесты Range, такие как:
если балл> 89 балл = 'A',
иначе, если балл> 79 балл = 'B' ...
Почему бы просто не сказать: если оценка> = 90?
Ответы:
В языках программирования с фигурными скобками и массивами , начинающимися с нуля , принято писать
for
циклы следующим образом:Это пересекает все элементы в массиве и является наиболее распространенным случаем. Это позволяет избежать использования
<=
или>=
.Единственный раз, когда это нужно будет изменить, - это когда вам нужно пропустить первый или последний элемент, или пересечь его в противоположном направлении, или пересечь его из другой начальной точки или в другую конечную точку.
Для коллекций, в языках, которые поддерживают итераторы, более распространено видеть это:
Который полностью избегает сравнений.
Если вы ищете жесткое и быстрое правило относительно того, когда использовать
<=
против<
, его нет; используйте то, что лучше всего выражает ваши намерения. Если ваш код должен выражать понятие «меньше или равно 55 милям в час», то он должен сказать<=
, что нет<
.Чтобы ответить на ваш вопрос о диапазонах оценок,
>= 90
имеет больше смысла, потому что 90 является фактическим граничным значением, а не 89.источник
for
таких циклов. Формаfor
цикла, которую я предоставил здесь, будет мгновенно узнаваема любым разработчиком с небольшим опытом. Если вы хотите получить более конкретный ответ, основанный на более конкретном сценарии, вы должны включить его в свой вопрос.Это не важно
Но ради аргумента давайте проанализируем два варианта:
a > b
противa >= b
.Подожди! Это не эквивалентно!
Хорошо, тогда
a >= b -1
противa > b
илиa > b
противa >= b +1
.Хм,
a >b
иa >= b
оба выглядят лучше, чемa >= b - 1
иa >= b +1
. Что это вообще такое1
? Поэтому я бы поспорил, что любая выгода от наличия>
вместо>=
или наоборот устраняется необходимостью добавления или вычитания случайных1
s.Но что, если это число? Это лучше сказать
a > 7
илиa >= 6
? Подожди секунду. Мы серьезно спорим, лучше ли использовать>
vs>=
и игнорировать жестко закодированные переменные? Таким образом, это действительно становится вопросом о томa > DAYS_OF_WEEK
, лучше лиa >= DAYS_OF_WEEK_MINUS_ONE
... или этоa > NUMBER_OF_LEGS_IN_INSECT_PLUS_ONE
противa >= NUMBER_OF_LEGS_IN_INSECT
? И мы вернулись к добавлению / вычитанию1
s, только на этот раз в именах переменных. Или, может быть, обсуждает, лучше ли использовать порог, лимит, максимум.И похоже, что нет общего правила: это зависит от того, что сравнивается
Но на самом деле, есть гораздо более важные вещи, которые нужно улучшить в своем коде, и гораздо более объективные и разумные рекомендации (например, ограничение X-символов на строку), которые все еще имеют исключения.
источник
>
против>=
или обсуждение того, имеет ли смысл обсуждение>
против>=
? хотя, вероятно, лучше избегать обсуждения этого: pВ вычислительном отношении нет разницы в стоимости при использовании
<
или>
по сравнению с<=
или>=
. Он вычисляется одинаково быстро.Однако большинство циклов for будет считать от 0 (потому что многие языки используют индексирование 0 для своих массивов). Таким образом, канонический цикл for в этих языках
выполнение этого с помощью a
<=
потребовало бы добавить -1 где-нибудь, чтобы избежать одной ошибкиили
Конечно, если в языке используется индексирование на основе 1, вы должны использовать <= в качестве ограничивающего условия.
Ключ заключается в том, что значения, выраженные в условии, являются значениями из описания проблемы. Читать чище
для полуоткрытого интервала, чем
и должны сделать математику, чтобы знать, что между 19 и 20 не может быть значения
источник
for(markup = 5; markup <= MAX_MARKUP; ++markup)
. Все остальное было бы слишком сложным.Я бы сказал, что дело не в том, должны ли вы использовать> или> =. Смысл в том, чтобы использовать все, что позволяет писать выразительный код.
Если вы обнаружите, что вам нужно добавить / вычесть один, рассмотрите возможность использования другого оператора. Я считаю, что хорошие вещи случаются, когда вы начинаете с хорошей моделью своего домена. Тогда логика пишет сама.
Это гораздо более выразительно, чем
В других случаях предпочтителен другой способ:
Намного лучше чем
Пожалуйста, извините за "примитивную одержимость". Очевидно, вы хотели бы использовать здесь Velocity- и Money-type соответственно, но я для краткости опустил их. Дело в том, что: используйте более краткую версию, которая позволит вам сосредоточиться на бизнес-проблеме, которую вы хотите решить.
источник
Как вы указали в своем вопросе, проверка на равенство по переменным с плавающей точкой не является надежной.
То же самое относится
<=
и к>=
.Однако для целочисленных типов такой проблемы с надежностью нет. По моему мнению, автор высказывала свое мнение о том, что является более читабельным.
Согласны ли вы с ним или нет, это, конечно, ваше мнение.
источник
<
или<=
основываться на том, что наиболее естественно для конкретной проблемы, которую я решаю. Как уже отмечали другие, цикл FOR<
имеет больше смысла в языках C-типа. Есть другие варианты использования, которые одобряют<=
. Используйте все инструменты в вашем распоряжении, когда и где это уместно.for (unsigned int i = n; i >= 0; i--)
или ,for (unsigned int i = x; i <= y; i++)
еслиy
случаетсяUINT_MAX
. Ой, эти петли навсегда.Каждый из отношений
<
,<=
,>=
,>
а также==
и!=
имеют примеры использования для сравнения двух значений с плавающей точкой. Каждый из них имеет конкретное значение, и следует выбрать соответствующий.Я приведу примеры для случаев, когда вам нужен именно этот оператор для каждого из них. (Будьте в курсе NaNs, хотя.)
f
которая принимает значение с плавающей запятой в качестве входных данных. Для того , чтобы ускорить вычисления, вы решили добавить кэш самых последних вычисленных значений, то есть, отображение таблицы поискаx
вf(x)
. Вы действительно хотите использовать==
для сравнения аргументов.x
? Вы, вероятно, хотите использоватьx != 0.0
.x
в единичном интервале?(x >= 0.0) && (x < 1.0)
это правильное условие.d
матрицы и хотите сказать, положительно ли она определена? Нет причин использовать что-либо еще, кромеd > 0.0
.alpha <= 1.0
.Математика с плавающей точкой (в общем) не является точной. Но это не значит, что вы должны бояться этого, относиться к нему как к магии и, конечно, не всегда относиться к двум величинам с плавающей запятой, равным, если они находятся внутри
1.0E-10
. Это действительно нарушит вашу математику и вызовет все странные вещи.x != 0.0
иy
является конечным значением с плавающей точкой,y / x
не обязательно быть конечным. Но может быть уместно узнать,y / x
не является ли оно конечным из-за переполнения или потому, что операция не была математически хорошо определена с самого начала.x
должен быть в единичном интервале [0, 1), я был бы очень расстроен, если бы он вызвал ошибку подтверждения при вызове с помощьюx == 0.0
илиx == 1.0 - 1.0E-14
.1.0E-30
, ничего не получится. Все, что вы делали, это увеличивало вероятность дать неправильный ответ.alpha
могут повлиять ошибки округления, и, следовательно, онalpha <= 1.0
может быть истинным, даже если истинное математическое значение для выраженияalpha
было действительно больше 1. Но с этим вы ничего не могли бы поделать.Как всегда в разработке программного обеспечения, обрабатывайте ошибки на соответствующем уровне и обрабатывайте их только один раз. Если вы добавляете ошибки округления порядка
1.0E-10
(кажется, это магическое значение, которое использует большинство людей, я не знаю почему) каждый раз, когда вы сравниваете величины с плавающей запятой, вы скоро будете иметь ошибки порядка1.0E+10
...источник
Тип условия, используемый в цикле, может ограничивать виды оптимизаций, которые может выполнять компилятор, к лучшему или к худшему. Например, учитывая:
компилятор может предположить, что вышеприведенное условие должно заставить цикл завершиться после цикла n-го прохода, если n не может 65535, и цикл может выйти каким-либо иным способом, кроме того, что i превысит n. Если эти условия применимы, компилятор должен сгенерировать код, который заставит цикл работать до тех пор, пока что-либо, кроме указанного выше условия, не заставит его завершиться.
Если цикл был записан как:
тогда компилятор может с уверенностью предположить, что цикл никогда не должен будет выполняться более n раз и, таким образом, сможет генерировать более эффективный код.
Обратите внимание, что любое переполнение со знаком типов может иметь неприятные последствия. Данный:
Компилятор может переписать это как:
Такой цикл будет вести себя идентично исходному, если в вычислениях не будет переполнения, но он может работать вечно даже на аппаратных платформах, где целочисленное переполнение обычно имеет согласованную семантику обтекания.
источник