Здесь существует две отделимых проблемы. Каждый - имеет ли двойное достаточно точности для содержания всех битов, в которых Вы нуждаетесь, и другой то, где она может представить Ваши числа точно.
Что касается точного представления, Вы правы быть осторожными, потому что точная десятичная дробь как 1/10 не имеет никакого точного двоичного дубликата. Однако, если Вы знаете, что Вам только нужны 5 десятичных цифр точности, можно использовать , масштабировался арифметика, в которой Вы воздействуете на числа, умноженные на 10^5. Так, например, если Вы хотите представить 23.7205 точно, Вы представляете его как 2372050.
Позволяют нам видеть, существует ли достаточно точности: двойная точность дает Вам 53 бита точности. Это эквивалентно 15 + десятичные цифры точности. Таким образом, это позволило бы Вам пять цифр после десятичной точки и 10 цифр перед десятичной точкой, которая кажется вполне достаточной для Вашего приложения.
я поместил бы этот код C в.h файл:
typedef double scaled_int;
#define SCALE_FACTOR 1.0e5 /* number of digits needed after decimal point */
static inline scaled_int adds(scaled_int x, scaled_int y) { return x + y; }
static inline scaled_int muls(scaled_int x, scaled_int y) { return x * y / SCALE_FACTOR; }
static inline scaled_int scaled_of_int(int x) { return (scaled_int) x * SCALE_FACTOR; }
static inline int intpart_of_scaled(scaled_int x) { return floor(x / SCALE_FACTOR); }
static inline int fraction_of_scaled(scaled_int x) { return x - SCALE_FACTOR * intpart_of_scaled(x); }
void fprint_scaled(FILE *out, scaled_int x) {
fprintf(out, "%d.%05d", intpart_of_scaled(x), fraction_of_scaled(x));
}
существует, вероятно, несколько грубых мест, но этого должно быть достаточно для запущения Вас.
Никакие издержки для дополнения, стоимости умножения или делятся, удваивается.
, Если у Вас есть доступ к C99, можно также попробовать масштабируемую целочисленную арифметику с помощью int64_t
64-разрядный целый тип. То, которое быстрее, будет зависеть от Вашей аппаратной платформы.
Хотя для меня это редкость, иногда мне кажется, что написание в такой форме в некоторых случаях приводит к наиболее ясному коду. Выберите форму, которая обеспечивает максимальную ясность. Компилятору все равно, и он должен сгенерировать по существу (возможно, в точности) тот же код.
Тем не менее, было бы проще определить логическую переменную, которой присвоено условие в операторе if (), а затем написать свой код в качестве отрицания этой переменной:
bool myCondition = (....);
if (!myCondition)
{
...
}
В этих случаях вы можете абстрагировать логику проверки в самом классе , чтобы не загромождать код вашего приложения.
Например
class MyClass
{
public string Prop{ get; set; }
// ... snip ...
public bool IsValid
{
bool valid = false;
if((value != null) &&
(!string.IsNullOrEmpty(value.Prop)) &&
(possibleValues.Contains(value.prop)))
{
valid = true
}
return valid;
}
// ...snip...
}
Теперь ваш код приложения
MyClass = value = GetValueFromSomewhere();
if( value.IsValie == false )
{
// Handle bad case here...
}
Я бы не стал делать это на C #. Но я делаю это на Python, потому что в Python есть ключевое слово, означающее «ничего не делать»:
if primary_condition:
pass
elif secondary_condition1:
do_one_thing()
elif secondary_condition2:
do_another_thing()
Можно сказать, что {}
функционально эквивалентно pass
, что это. Но это (для людей) семантически не эквивалентно. pass
означает «ничего не делать», а для меня {}
обычно означает «раньше был код, а сейчас его нет».
Но в целом, если Я дохожу до того, что даже возникает проблема, затрудняет ли чтение !
перед условием, у меня проблема. Если я пойму, что пишу такой код:
while (keypress != escape_key && keypress != alt_f4_key && keypress != ctrl_w_key)
, мне будет совершенно ясно, что то, чего я действительно буду хотеть в долгосрочной перспективе, будет примерно таким:
Следующий стиль, в котором один блок должен быть пустым от if-else, считается плохим. для хорошей практики программирования, если вам не нужно писать в блоке if, вам нужно поставить (!) 'Not' в блок if .. нет необходимости писать else
If (условие) // пусто еще // код
можно заменить на
if (! условие) // код
это также сохранение дополнительной строки кода ..
1-й:
object value = GetValueFromSomeAPIOrOtherMethod();
var isValidValue = (value != null) && (!string.IsNullOrEmpty(value.Prop)) && (possibleValues.Contains(value.prop));
if(!isValidValue)
{
// Do my stuff here, like error handling
}
2cnd:
object value = GetValueFromSomeAPIOrOtherMethod();
if(!isValidAPIValue(value))
{
// Do my stuff here, like error handling
}
Все ли выражения действительно одинаковы? В языках, поддерживающих короткое замыкание, изменение между «и» и «или» может быть фатальным. Помните об использовании && в качестве защиты от проверки других условий.
Будьте осторожны при преобразовании. Сделано больше ошибок, чем можно было ожидать.
Я всегда пытаюсь преобразовать такие большие условия в свойство или метод для удобства чтения. Итак, это:
object value = GetValueFromSomeAPIOrOtherMethod();
if((value == null) || (string.IsNullOrEmpty(value.Prop)) || (!possibleValues.Contains(value.prop)))
{
// Do my stuff here, like error handling
}
становится примерно таким:
object value = GetValueFromSomeAPIOrOtherMethod();
if (IsValueUnacceptable(value))
{
// Do my stuff here, like error handling
}
...
/// <summary>
/// Determines if the value is acceptable.
/// </summary>
/// <param name="value">The value to criticize.</param>
private bool IsValueUnacceptable(object value)
{
return (value == null) || (string.IsNullOrEmpty(value.Prop)) || (!possibleValues.Contains(value.prop))
}
Теперь вы всегда можете повторно использовать метод / свойство, если это необходимо, и вам не нужно слишком много думать о методе потребления.
Конечно,
Мне нравится вторая версия. Это делает код более чистым. На самом деле это одна из вещей, которую я бы попросил исправить во время проверки кода.
Обычно я отвечаю отрицательно .... но я думаю, что хороший стиль программирования основан на согласованности .....
поэтому, если у меня много выражений, выглядят как
if (condition)
{
// do something
}
else
{
// do something else
}
Затем случайный «пустой» блок if подходит, например
if (condition)
{ } // do nothing
else
{
// do something else
}
Причина этого в том, что если ваши глаза что-то видят несколько раз, они с меньшей вероятностью заметят изменение, например крошечный «!». Так что, хотя это плохо делать изолированно, очень вероятно, что кто-то, обслуживающий код, в будущем поймет, что этот конкретный if..else ... отличается от остальных ...
Другой конкретный сценарий, где это может быть приемлемо для какой-то логики конечного автомата, например
if (!step1done)
{} // do nothing, but we might decide to put something in here later
else if (!step2done)
{
// do stuff here
}
else if (!step3done)
{
// do stuff here
}
. Это явно подчеркивает последовательный поток состояний, шаги, выполняемые в каждом (даже если это ничего). Я бы предпочел это чем-то вроде ...
if (step1done && !step2Done)
{
// do stuff here
}
if (step1done && step2done && !state3Done)
{
// do stuff here
}
Иногда я попадаю в похожую, но немного отличающуюся ситуацию:
if ( TheMainThingIsNormal () )
; // nothing special to do
else if ( SomethingElseIsSpecial () ) // only possible/meaningful if ! TheMainThingIsNormal ()
DoSomethingSpecial ();
else if ( TheOtherThingIsSpecial () )
DoSomethingElseSpecial ();
else // ... you see where I'm going here
// and then finish up
Единственный способ удалить пустой блок - это создать дополнительную вложенность:
if ( ! TheMainThingIsNormal () )
{
if ( SomethingElseIsSpecial () )
DoSomethingSpecial ();
else if ( TheOtherThingIsSpecial () )
DoSomethingElseSpecial ();
else // ...
}
Я не проверяю исключение или условия проверки - я просто занимаюсь особыми или разовыми случаями - поэтому я не могу просто выручить раньше времени.
Я считаю это неприемлемым (хотя я ' я уверен, что делал это в прошлом), чтобы иметь такой пустой блок. Это подразумевает, что что-то должно быть сделано.
Я вижу, что в других вопросах говорится, что второй способ более удобочитаем. Лично я говорю, что ни один из ваших примеров не особо читабелен. В приведенных вами примерах требуется метод "IsValueValid (...)".
Я делаю это, когда мой мозг может легко понять логику успеха, но трудно понять логику неудачи.
Я обычно просто добавляю комментарий "// no op ", чтобы люди знали, что это не ошибка.
Если я вижу «если», я ожидаю, что оно что-то сделает.
if(!condition)
гораздо более читабельно.
if(condition) {
//do nothing
}
else {
//do stuff
}
по сути гласит: «Если мое условие выполнено, ничего не делайте, в противном случае сделайте что-нибудь ».
Если мы хотим читать ваш код как прозу (какой хороший самодокументирующийся код должен быть в состоянии читать таким образом) , это просто слишком многословно и вводит больше концепций, чем необходимо отпишусь. Используйте знак "!".
Ваш вопрос аналогичен моему ответу (упрощение условий) на любимое игнорирование программиста pet peeve's
Для языков, которые не поддерживают конструкцию до, объединение в цепочку множественных NOTs заставляет наши глаза кровоточить
Какой из них легче читать?
Это:
while (keypress != escape_key && keypress != alt_f4_key && keypress != ctrl_w_key)
Или это:
until (keypress == escape_key || keypress == alt_f4_key || keypress == ctrl_w_key)
Я считаю, что последнее легче грокнуть, чем первое. Первый включает слишком много НЕ, а условия И делают логику более липкой , вынуждают вас прочитать все выражение, прежде чем вы сможете быть уверены, что ваш код действительно правильный, и это будет намного сложнее читать, если ваша логика включает сложную логику (влечет за собой объединение большего количества операторов AND, очень липких).
В колледже в нашем классе изучают теорему Де Моргана. Я действительно ценю, что логику можно упростить с помощью его теоремы. Итак, для языковой конструкции, которая не поддерживает оператор until, используйте это:
while !(keypress == escape_key || keypress == alt_f4_key || keypress == ctrl_w_key)
Но поскольку C не поддерживает оператор while / if без скобок, нам нужно добавить скобки в наш код DeMorgan'd:
while (!(keypress == escape_key || keypress == alt_f4_key || keypress == ctrl_w_key))
И это что могло спровоцировать комментарий Дэна Си о том, что код ДеМоргана больше режет ему глаза на мой ответ на любимое невежество программиста, домашнее раздражение
Но на самом деле, код ДеМоргана легче читать, чем иметь несколько NOTS и липкое AND
[EDIT]
Ваш код (код ДеМоргана):
object value = GetValueFromSomeAPIOrOtherMethod();
if ( value == null || string.IsNullOrEmpty(value.Prop)
|| !possibleValues.Contains(value.prop) )
{
// Do my stuff here, like error handling
}
.. в порядке. Фактически, это то, что делают большинство программистов (особенно из языков, которые не имеют конструкций try / catch / finally с самого начала), чтобы убедиться, что выполняются условия (например, отсутствие использования нулевых указателей, правильные значения и т. Д.) перед продолжением операций.
Примечание: я взял на себя смелость удалить лишние скобки в вашем коде, возможно, вы пришли с языка Delphi / Pascal.
Это плохой стиль, рассмотрите несколько очень полезных альтернатив:
Используйте стиль защитного предложения :
object value = GetValueFromSomeAPIOrOtherMethod();
if((value != null) && (!string.IsNullOrEmpty(value.Prop)) && (possibleValues.Contains(value.prop)))
{
return;
}
// do stuff here
Извлеките условное выражение в его собственный метод, это сохраняет вещи логично и легко читается:
bool ValueHasProperty(object value)
{
return (value != null) && (!string.IsNullOrEmpty(value.Prop)) && (possibleValues.Contains(value.prop));
}
void SomeMethod()
{
object value = GetValueFromSomeAPIOrOtherMethod();
if(!ValueHasProperty(value))
{
// do stuff here
}
}
Хотя это не всегда практично, я обычно предпочитаю изменить
if (complexcondition){} else {/*stuff*/}
на
if (complexcondition) continue;
/*stuff*/
(или выйти с return
, break
, так далее.). Конечно, если условие слишком сложное, вы можете заменить его несколькими условиями, все из которых заставят код нарушить то, что он делает. Это в основном относится к типам кода проверки и проверки ошибок, от которых вы, вероятно, захотите выйти, если что-то пойдет не так.
Извлеките ваши условия, затем позвоните по телефону
if(!ConditionsMetFor(value))
{
//Do Something
}
Простое использование части else недопустимо. Вам не нужно утруждать себя применением правила Де-Моргана, только не всего выражения. То есть перейдите от if (cond)
к if (! (Cond))
.
Я считаю это совершенно неприемлемым.
Единственная причина - избегать единственного отрицания и пары скобок вокруг выражения. Я согласен, что выражения в вашем примере ужасны, но они недопустимо запутаны с самого начала! Разделите выражение на части приемлемой ясности, сохраните их в логических значениях (или сделайте из них методы) и объедините их, чтобы создать условие if-statement.
Один похожий дизайн, который я часто использую, - это ранний выход. Я не пишу такой код:
if (validityCheck1)
{
if (validityCheck2)
{
// Do lots and lots of things
}
else
{
// Throw some exception, return something, or do some other simple cleanup/logic (version 2)
}
}
else
{
// Throw some exception, return something, or do some other simple cleanup/logic. (version 1)
}
Вместо этого я пишу это:
if (!validityCheck1)
{
// Throw some exception, return false, or do some other simple logic. (version 1)
}
if (!validityCheck2)
{
// Throw some exception, return false, or do some other simple logic. (version 2)
}
// Do lots and lots of things
У этого есть два преимущества:
Лишь несколько вариантов ввода недопустимы, и они просты в обращении. С ними нужно работать немедленно, чтобы мы могли как можно скорее выбросить их из нашей ментальной модели и полностью сосредоточиться на важной логике. Особенно, когда во вложенных операторах if выполняется несколько проверок действительности.
Блок кода, который обрабатывает допустимые варианты, обычно будет самой большой частью метода и будет содержать собственные вложенные блоки. Он будет намного менее загроможден, если сам этот блок кода не вложен (возможно, несколько раз) в оператор if.
Таким образом, код будет более читаемым и его легче рассуждать.
Я должен предисловие к этому, сказав, что мои личные предпочтения, но я обычно вытаскиваю логику проверки из кода в ее собственную функцию проверки. В этот момент ваш код становится более «аккуратным», если вы просто говорите:
if(!ValidateAPIValue(value))
Это, на мой взгляд, кажется более кратким и понятным.
Наличие пустого блока if с операторами в else - это ... просто плохой стиль. Извини, это одна из моих любимых мозолей. В этом нет ничего функционально неправильного, просто из-за него у меня текут глаза.
Просто! из оператора if и поместите туда свой код. ИМХО это уменьшает шум и делает код более читабельным.
Это не очень хорошая практика. Если бы вы использовали рубин, вы бы сделали:
unless condition
do something
end
Если ваш язык не позволяет этого, вместо выполнения
if(a){}else{something}
выполните
if(!a){something}
I'm a fan of DeMorgan's Rule which takes your ex3 and produces your ex2. An empty if block is a mental block imo. You have to stop to read the nothing that exists - then you have to wonder why.
If you have to leave comments like // This left blank on purpose; then the code isn't very self-explanatory.