pow() некорректно работает если используется инкремент или декремент в его параметрах. Задание: Совершая обход так: 1 3 4 10 2 5 9 11 6 8 12 15 7 13 14 16 заполнить матрицу а такими значениями: b11b12...bnn
Kod(Показать/Скрыть)
#include <cmath>#include <iostream>#include <windows.h>usingnamespacestd;
main()
{
int M, N;
cout << "Insert N: ";
cin >> N;
int b[N];
cout << "Insert b[i]: ";
for (int i = 0; i < N; i++)
cin >> b[i];
int a[M = N][N];
int i = 0, j = 0, k = 0;
while (i < M || j != N - 1)
{
while (i < M && 0 <= j) a[i++][j--] = pow(b[k++ / N], k % N + 1);
if (i == M){i--; j++;}
while (0 <= i && j < N - 1) a[i--][++j] = pow(b[k++ / N], k % N + 1);
i++;
if (j == N - 1) i++;
else j++;
}
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
{
cout.width(4);
cout << a[i][j];
}
cout << endl;
}
system("pause");
}
В таком исполнении pow(b[k++ / N], k % N + 1); работает так как надо (еще недавно и так не работал, но теперь почему-то работает):
Главное, ничего не сказал, в чем корявость, что не так, что передаешь в функцию, в конце концов, ОТКУДА эта функция, из <math.h> или из <cmath>, но
Цитата
работает коряво
Интересная постановка вопроса. У меня вот не работает коряво, работает как положено. Если надо - кину код...
sheka
8.10.2011 4:01
Исправил.
IUnknown
8.10.2011 5:23
Ты на самом деле думаешь, что оба эти фрагмента делают одно и то же? Вынужден тебя разочаровать, это не так. Вот тебе простейший тест, доказывающий это:
1) добавляешь небольшую функцию, по имени pow, которая не только вычисляет значение xy, но еще и печатает, для каких аргументов она сработала:
int pow(int x, int y)
{
cout << "pow : x = " << x << " y = " << y << endl;
returnstd::pow(x, y);
}
, больше в коде ничего менять не надо, тебе и так будет понятно что произойдет дальше.
Итак. Запускаем с pow(b[k++ / N], k % N + 1)
Результат(Показать/Скрыть)
Insert N: 4 Insert b[i]: 1 2 3 4 pow : x = 1 y = 1 pow : x = 1 y = 2 pow : x = 1 y = 3 pow : x = 1 y = 4 pow : x = 2 y = 1 pow : x = 2 y = 2 pow : x = 2 y = 3 pow : x = 2 y = 4 pow : x = 3 y = 1 pow : x = 3 y = 2 pow : x = 3 y = 3 pow : x = 3 y = 4 pow : x = 4 y = 1 pow : x = 4 y = 2 pow : x = 4 y = 3 pow : x = 4 y = 4 1 1 1 9 1 2 3 27 4 16 81 64 8 4 16 256 Press any key to continue . . .
А теперь - запускаем с pow(b[k / N], ++k % N + 1)
Результат(Показать/Скрыть)
Insert N: 4 Insert b[i]: 1 2 3 4 pow : x = 1 y = 2 pow : x = 1 y = 3 pow : x = 1 y = 4 pow : x = 2 y = 1 pow : x = 2 y = 2 pow : x = 2 y = 3 pow : x = 2 y = 4 pow : x = 3 y = 1 pow : x = 3 y = 2 pow : x = 3 y = 3 pow : x = 3 y = 4 pow : x = 4 y = 1 pow : x = 4 y = 2 pow : x = 4 y = 3 pow : x = 4 y = 4 pow : x = 4673632 y = 1 1 1 2 27 1 4 9 81 8 3 4 256 16 16 644673632 Press any key to continue . . .
И что, ты по-прежнему считаешь, что глючит pow? Может, не надо извращаться при вычислении параметров и добиваться UB (неопределенного поведения), чего ты как раз и добился? Поведение не определено, в зависимости от компилятора, фазы Луны и погоды на Сатурне будут выдаваться разные результаты.
P.S. Кстати, компилятор же предупреждает тебя, что в коде не все в порядке:
In function 'int main()': main.cpp (24) warning: operation on 'k' may be undefined main.cpp (27) warning: operation on 'k' may be undefined === Build finished: 0 errors, 2 warnings (0 minutes, 1 seconds) ===
Неужели это не наводит на размышления? Или опять не обращаем внимания на предупреждения?
TarasBer
8.10.2011 22:27
Я бы вообще запретил ++ в составе сложных выражений.
sheka
9.10.2011 2:05
Хм, я как бы понимаю, что вначале значение пропустило, а поэтому потом что-то дорисовало. Но я думал что в этом виноват pow, и никак не ++. Компилятор GNU GCC (CodeBlocks 10.05) ничего не выдает. Объясните, пожалуйста, что делает ++ ужасного.
IUnknown
9.10.2011 2:27
Цитата
Компилятор GNU GCC (CodeBlocks 10.05) ничего не выдает.
Неправда. Зайди в Project -> Build Options, в Compiler Flags включи "Enable all compiler warnings" (которая -Wall), и пересобери проект. Можешь узнать очень много интересного
Теперь по Борщову вопросу, что же такого делает ++. Ответ очень прост: изменяет значение переменной. Вот такой у этого оператора побочный эффект. Как бы, ничего страшного, ведь для этого инкремент и предназначен. Ан нет. Тут есть еще вот какая история: в С/С++ не определен ни порядок вычисления выражений, ни порядок вычисления параметров функции (как следствие - не определен и порядок возникновения побочных эффектов). То есть, сказать по:
while (i < M && 0 <= j) a[i++][j--] = pow(b[k / N], (++k) % N + 1);
, что будет выполнено раньше, вычисление первого параметра со старым значением k, а потом инкремент и вычисление второго параметра с новым значением, или наоборот, сначала значение k инкрементируется, и вычислится второй параметр для pow(), а потом с той, уже увеличенной k, будет вычисляться первый параметр - не может никто. Это компиляторозависимо, и, кроме всего прочего, зависит от оптимизатора, ибо в конечном счете он выбирает, в каком порядке вычислять параметры, чтоб было как можно оптимальней. А это уже неопределенное поведение со всеми вытекающими последствиями: нестабильная работа программы (ты ж сам говорил, что раньше не работало, теперь вдруг заработало, помнишь? Явный признак, что что-то не так), и предупреждение, выдаваемое компилятором. Кстати, с первым вариантом:
while (i < M && 0 <= j) a[i++][j--] = pow(b[k++ / N], k % N + 1);
- абсолютно та же история, побочный эффект присутствует и там, а что если сначала вычислится второй параметр, а только потом - первый? Упс... Опять перестанет работать...
Для гарантированного порядка вычисления - используй временные переменные, тогда UB не будет.
Кстати, разницу между префиксным и постфиксным ++ (да и -- тоже) знаешь?
Lapp
9.10.2011 10:42
Цитата(sheka @ 8.10.2011 23:05)
Но я думал что в этом виноват pow, и никак не ++.
Я извиняюсь, что встреваю. Просто "понравился" образ мысли, не смог удержаться )). Шека, тут виноват не ++, и не Pow(), виноват ты сам. Во всех случаях прежде всего надо подозревать себя самого. Всякий раз, когда тебе хочется написать что-то вроде "pow() некорректно работает" - вспомни, что миллионы и миллионы программистов работают и не жалуются.. ))
Я согласен, ++ - это жутко хитрая штука. Я помню случай, когда я искал ошибку дня два в довольно несложном коде.. и еще несколько случаев помельче - он же не только в C/C++, он мне портил кровь и в PHP, и в Java.. Но я все равно его очень люблю и запрещать не стал бы )).
P.S. Я думал, что на этом форуме, благодаря стараниям volvo/IUnknown (и не только), никто не будет вот так сразу валить на компилятор..
Не думал, что на http://lurkmore.ru есть что-то такое издевательски поучительное
IUnknown
13.10.2011 21:28
Я не про вычисление логических выражений. Я про
int f();
int g();
// ...
test(f(), g());
Какая из функций будет вызвана первой (перефразируем, какой аргумент функции test будет вычисляться сначала), f() или g()? Стандарт на этот вопрос ответа не даёт.
Равно, и на вопрос, как будет вычисляться x+y-z. Сначала x+y, а потом отнимут z, или все-таки сначала y-z, а потом прибавят x (причем тут даже на скобки С++ плевал с высокой колокольни, "приоритеты операций одинаковы - как хочу, так и буду делать, тебя не спросил")... Это тоже называется "порядок не определён"...
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.