некоторые вопросы по поводу порядка оценки и сравнения

В ходе собеседования на C / C ++ я нашел несколько вопросов, на которые я не ответил правильно, я использовал Visual C ++ для проверки результатов, надеюсь, вы поможете мне понять их:

1)

int i=-3, j=2, k=0, m;
m = ++i && ++j || ++k; // k not incremented why ???
cout << i << " " << j << " " << k << " " << m; // -2 3 0 1 why it's not -2 3 1 1 !!!

=> почему k не увеличивается, особенно перед ним стоит ++? и я хочу знать порядок выполнения такой строки, я не мог сделать это в режиме отладки.

Можете ли вы дать мне правило, чтобы следовать таким оценкам, когда есть такие вещи, как ++ переменная или переменная ++ Спасибо

2) почему это сравнение неверно?

float a = 5.2;
if(a == 5.2) // false
{}

когда я добавляю float cast к 5.2, это работает ….

3)

int n()
{
static int x = 0;
return x++;
}

=> Я думал, что мы всегда возвращаем 0, потому что я думал, что компилятор переведет «return x ++» в: return x; х ++; тогда мы никогда не будем выполнять приращение …

-4

Решение

В следующий раз, когда у вас есть несколько вопросов, пожалуйста, задавайте их отдельно.

Ответ на вопрос 1:

Несколько вещей:

  1. Оба && а также || операторы форсируют оценку слева направо1, и оба вводят точка последовательности; левый операнд будет оценен, и все побочные эффекты будут применены до того, как правый операнд будет оценен;

  2. Оба && а также || операторы короткое замыкание — если значение выражения может быть определено из левого операнда, то правый операнд не будет оцениваться;

    • в выражении a || b, b не будет оцениваться, если a ненулевой;
    • в выражении a && b, b не будет оцениваться, если a ноль;
  3. && имеет более высокий приоритет, чем ||, так a || b && c анализируется как a || (b && c);

  4. x++ оценивает к текущей стоимости xи как побочный эффект приращений x;

  5. ++x оценивает к текущей стоимости x плюс 1, и как побочный эффект приращений x,

Итак, выражение

++i && ++j || ++k

является разобранный как

(++i && ++j) || ++k

а также оценивали следующее:

  1. ++i оценивается; результат -2 что не ноль, так что
  2. ++j оценивается; результат 3, так:
  3. и то и другое -2 а также 3 ненулевые, поэтому:
  4. ++i && ++j оценивается в 1, так что:
  5. ++k не оценивается вообще.

Ответ на вопрос 2:

Опять несколько вопросов:

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

  2. Выражение константы с плавающей точкой 5.2 имеет тип doubleне float; сделать это float, вы бы использовали f суффикс — 5.2f;

  3. float а также double имеют разные представления (double выделяет больше битов как экспоненте, так и дроби), поэтому они будут хранить разные приближения для одинаковых значений, поэтому == сравнение не сработало.

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

Ответ на вопрос 3:

Вы возвращаете результат выражение x++, но выражение все еще имеет побочный эффект увеличения x (и побочный эффект применяется до конца return заявление).


1. Большинство операторов в C делают не форсировать определенный порядок оценки — учитывая выражение как a + b * c, каждый из a, b, а также c можно оценить в любом порядке. результат из b * c должно быть известно, прежде чем он может быть добавлен к результату a, но это не значит, что либо b или же c должно быть оценивали до a,

3

Другие решения

Вопрос № 1:

&& оператор имеет приоритет над ||, так что это будет оцениваться в первую очередь. Оба условия (++i а также ++j) имеют предварительное приращение, поэтому сначала они увеличиваются до -2 и 3 соответственно, затем они становятся AND. В C ++ 0 — это false а все остальное есть true, В этом случае оба условия true (то есть ненулевой), поэтому && возвращается true, Теперь пришло время проверить true || ++k, Здесь начинается оптимизация: с true || anything всегда будет trueкомпилятор даже не проверяет выражение. То есть он не выполняет его. А также k не увеличивается. Вот почему очень плохая привычка иметь код внутри if-операторов что-то делает — вы не можете быть уверены, что он будет выполняться, в зависимости от условия. если ты необходимость чтобы он работал, убедитесь, что он не помещен туда или его можно оптимизировать.

Вопрос № 2:

Арифметика с плавающей точкой сложна — точное представление числа часто невозможно, а числа, которые действительно используются, являются лишь очень близким приближением — достаточно близко, чтобы это выглядело, как будто это работает, но если вы проверяете каждый маленький бит, вы замечаете, что числа не то, на что они похожи. По умолчанию число рассматривается как double, double и floatхотя они выглядят одинаково, не одинаковы. Это уже было рассмотрено здесь: странный вывод по сравнению с float с литералом float. И я действительно рекомендую прочитать одну из связанных статей, эту: «Что каждый компьютерщик должен знать об арифметике с плавающей точкой»

Вопрос № 3:

Вы правы, что возвращаемое значение равно 0 (в первый раз!), Но затем вы думаете, что инструкция разбита на две части, первая из которых является return, что должно привести к пропуску второго (приращения). Нет, так не работает. Приращение выполняется в любом случае. Постинкремент работает следующим образом: сделайте копию, увеличьте оригинал, верните копию. То, что называется постинкрементом, видит исходное значение, но приращение делает происходить. И с тех пор x является static, значение будет сохранено, так что в следующий раз функция n() называется, начальное значение x будет 1. А потом 2, 3 и тд.

4

  1. C и C ++ работают по логике короткого замыкания.

Учтите следующее:

bool myBool = (1 || 0+6*4);

myBool оценим как можно скорее. В этом случае он будет иметь значение true, потому что левый аргумент в || правда. Прекращает оценку немедленно. То же самое касается &&, Вот почему идиоматично добавлять более вероятный регистр сбоя слева от логических операторов.

  1. Это неверно, потому что числа с плавающей точкой не могут быть полностью представлены в двоичном виде.

В этом случае, это действительно оценило бы как истинное. Однако рассмотрим следующий пример:

#include <iostream>

int main() {
double i = 0.1;
double total = 0.0;
for(int j = 0; j < 10000; j++) {
total+=i;
}

// total = 0.1*10000 = 1000... right?

std::cout << std::boolalpha << "total == 1000.0 ? " << (total == 1000.0) << std::endl;

return 0;
}

Вотэто вывод вышеуказанной программы. Сравнение чисел с плавающей запятой и двойников — сложная задача для вычислений. Будьте осторожны, делая это.

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

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

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector