Не очень понятно про оболочечные Данные,ячейки памяти могут наверно размер менять,какое это значение те же операции только ячейки больше,по скорости тоже самое |
Управляющие конструкции
5.7. Оператор цикла while – цикл с предусловием
while(условие) оператор;
Пока условие сохраняет значение true — в цикле выполняется оператор, иначе — действие цикла прекращается. Если условие с самого начала false, цикл сразу прекращается, и тело цикла не выполнится ни разу.
Цикл while обычно применяют вместо цикла for в том случае, если условия продолжения достаточно сложные. В отличие от цикла for в этом случае нет формально заданного счетчика цикла, и не производится его автоматического изменения. За это отвечает программист. Хотя вполне возможно использование как цикла for вместо while, так и наоборот. Многие программисты предпочитают пользоваться только циклом for как наиболее универсальным.
Пример:
i=1; x=0; while(i<=n){ x+=i;//эквивалентно x=x+i; i*=2;//эквивалентно i=2*i; };
В операторе while очень часто совершают ошибки, приводящие к неустойчивости алгоритмов из-за сравнения чисел с плавающей точкой на неравенство. Как мы знаем, сравнивать их на равенство в подавляющем большинстве случаев некорректно из-за ошибок представления таких чисел в компьютере. Но большинство программистов почему-то считает, что при сравнении на неравенство проблем не возникает, хотя это не так. Например, если организовать с помощью оператора while цикл с вещественным счетчиком, аналогичный разобранному в разделе, посвященному циклу for. Пример типичной ошибки в организации такого цикла приведен ниже:
double a=…; double b=…; double dx=…; double x=a; while(x<=b){ … x=x+dx; };
Как мы уже знаем, данный цикл будет обладать неустойчивостью в случае, когда на интервале от a до b укладывается целое число шагов. Например, при a=0, b=10, dx=0.1 тело цикла будет выполняться при x=0, x=0.1, …, x=9.9. А вот при x=10 тело цикла может либо выполниться, либо не выполниться – как повезет! Причина связана с конечной точностью выполнения операций с числами в формате с плавающей точкой. Величина шага dx в двоичном представлении чуть-чуть отличается от значения 0.1, и при каждом цикле систематическая погрешность в значении x накапливается. Поэтому точное значение x=10 достигнуто не будет, величина x будет либо чуть-чуть меньше, либо чуть-чуть больше. В первом случае тело цикла выполнится, во втором – нет. То есть пройдет либо 100, либо 101 итерация (число выполнений тела цикла).
5.8. Оператор цикла do...while – цикл с постусловием
do оператор; while(условие);
Если условие принимает значение false, цикл прекращается. Тело цикла выполняется до проверки условия, поэтому оно всегда выполнится хотя бы один раз.
Пример:
int i=0; double x=1; do{ i++; // i=i+1; x*=i; // x=x*i; } while(i<n);
Если с помощью оператора do…while организуется цикл с вещественным счетчиком или другой проверкой на равенство или неравенство чисел типа float или double, у него возникают точно такие же проблемы, как описанные для циклов for и while.
При необходимости организовать бесконечный цикл (с выходом изнутри тела цикла с помощью оператора прерывания) часто используют следующий вариант:
do{ … } while(true);
5.9. Операторы прерывания continue, break, return, System.exit
Довольно часто требуется при выполнении какого-либо условия прервать цикл или подпрограмму и перейти к выполнению другого алгоритма или очередной итерации цикла. При неструктурном программировании для этих целей служил оператор goto. В Java имеются более гибкие и структурные средства для решения этих проблем - операторы continue, break, return, System.exit:
- continue; – прерывание выполнения тела цикла и переход к следующей итерации (проверке условия) текущего цикла;
- continue имя метки; – прерывание выполнения тела цикла и переход к следующей итерации (проверке условия) цикла, помеченного меткой ( label );
- break; – выход из текущего цикла;
- break имя метки; – выход из цикла, помеченного меткой;
- return; – выход из текущей подпрограммы (в том числе из тела цикла) без возврата значения;
- return значение; – выход из текущей подпрограммы (в том числе из тела цикла) с возвратом значения;
- System.exit(n) –выход из приложения с кодом завершения n. Целое число n произвольно задается программистом. Если n=0, выход считается нормальным, в других случаях - аварийным. Приложение перед завершением сообщает число n операционной системе для того, чтобы программист мог установить, по какой причине произошел аварийный выход.
Операторы continue и break используются в двух вариантах – без меток для выхода из текущего (самого внутреннего по вложенности) цикла, и с меткой - для выхода из помеченного ей цикла. Меткой является идентификатор, после которого стоит двоеточие. Метку можно ставить непосредственно перед ключевым словом, начинающим задание цикла ( for, while, do ).
Пример использования continue без метки:
for(int i=1;i<=10;i++){ if(i==(i/2)*2){ continue; }; System.out.println("i="+i); };
В данном цикле не будут печататься все значения i, для которых i==(i/2)*2. То есть выводиться в окно консоли будут только нечетные значения i.
Еще один пример использования continue без метки:
for(int i=1;i<=20;i++){ for(int j=1;j<=20;j++){ if(i*j==(i*j/2)*2){ continue; }; System.out.println("i="+i+" j="+j+ " 1.0/(i*j-20)="+ (1.0/(i*j-20)) ); }; };
В этом случае будут выводиться значения i, j и 1.0/(i*j-20) для всех нечетных i и j от 1 до 19 . То есть будут пропущены значения для всех четных i и j:
i=1 j=1 1.0/(i*j-20)=-0.05263157894736842 i=1 j=3 1.0/(i*j-20)=-0.058823529411764705 i=1 j=5 1.0/(i*j-20)=-0.06666666666666667 i=1 j=7 1.0/(i*j-20)=-0.07692307692307693 i=1 j=9 1.0/(i*j-20)=-0.09090909090909091 i=1 j=11 1.0/(i*j-20)=-0.1111111111111111 i=1 j=13 1.0/(i*j-20)=-0.14285714285714285 i=1 j=15 1.0/(i*j-20)=-0.2 i=1 j=17 1.0/(i*j-20)=-0.3333333333333333 i=1 j=19 1.0/(i*j-20)=-1.0 i=3 j=1 1.0/(i*j-20)=-0.058823529411764705 i=3 j=3 1.0/(i*j-20)=-0.09090909090909091 i=3 j=5 1.0/(i*j-20)=-0.2 i=3 j=7 1.0/(i*j-20)=1.0 ... i=19 j=9 1.0/(i*j-20)=0.006622516556291391 i=19 j=11 1.0/(i*j-20)=0.005291005291005291 i=19 j=13 1.0/(i*j-20)=0.004405286343612335 i=19 j=15 1.0/(i*j-20)=0.0037735849056603774 i=19 j=17 1.0/(i*j-20)=0.0033003300330033004 i=19 j=19 1.0/(i*j-20)=0.002932551319648094
Пример использования continue с меткой:
label_for1: for(int i=1;i<=20;i++){ for(int j=1;j<=20;j++){ if(i*j==(i*j/2)*2){ continue label_for1; }; System.out.println("i="+i+" j="+j+ " 1.0/(i*j-20)="+ (1.0/(i*j-20)) ); }; };
В отличие от предыдущего случая, после каждого достижения равенства i*j==(i*j/2)*2 будет производиться выход из внутреннего цикла (по j), и все последующие j для таких значений i будут пропущены. Поэтому будут выведены только значения
i=1 j=1 1.0/(i*j-20)=-0.05263157894736842 i=3 j=1 1.0/(i*j-20)=-0.058823529411764705 i=5 j=1 1.0/(i*j-20)=-0.06666666666666667 i=7 j=1 1.0/(i*j-20)=-0.07692307692307693 i=9 j=1 1.0/(i*j-20)=-0.09090909090909091 i=11 j=1 1.0/(i*j-20)=-0.1111111111111111 i=13 j=1 1.0/(i*j-20)=-0.14285714285714285 i=15 j=1 1.0/(i*j-20)=-0.2 i=17 j=1 1.0/(i*j-20)=-0.3333333333333333 i=19 j=1 1.0/(i*j-20)=-1.0
Пример использования break без метки:
for(int i=1;i<=10;i++){ if( i+6== i*i ){ break; }; System.out.println("i="+i); };
Данный цикл остановится при выполнении условия i+6== i*i. То есть вывод в окно консоли будет только для значений i, равных 1 и 2.
Еще один пример использования break без метки:
for(int i=1;i<=20;i++){ for(int j=1;j<=20;j++){ if(i*j==(i*j/2)*2){ break; }; System.out.println("i="+i+" j="+j+ " 1.0/(i*j-20)="+ (1.0/(i*j-20)) ); }; };
В этом случае будут выводиться все значения i и j до тех пор, пока не найдется пара i и j, для которых i*j==(i*j/2)*2. После чего внутренний цикл прекращается – значения i, j и 1.0/(i*j-20) для данного и последующих значений j при соответствующем i не будут выводиться в окно консоли. Но внешний цикл (по i) будет продолжаться, и вывод продолжится для новых i и j. Результат будет таким же, как для continue с меткой для внешнего цикла.
Пример использования break с меткой:
label_for1: for(int i=1;i<=20;i++){ for(int j=1;j<=20;j++){ if(i*j==(i*j/2)*2){ break label_for1; }; System.out.println("i="+i+" j="+j+ " 1.0/(i*j-20)="+ (1.0/(i*j-20)) ); }; };
В этом случае также будут выводиться все значения i и j до тех пор, пока не найдется пара i и j, для которых i*j==(i*j/2)*2. После чего прекращается внешний цикл, а значит – и внутренний тоже. Так что вывод в окно консоли прекратится. Поэтому вывод будет только для i=1, j=1.
Краткие итоги
- В Java имеются: условный оператор if, оператор выбора switch, условное выражение …?... : … , операторы инкремента ++ и декремента --,
- В Java имеются операторы цикла: for, while – цикл с предусловием, do...while – цикл с постусловием. А также операторы прерывания циклов continue и break, подпрограмм - return, программы - System.exit.
- Сравнение на равенство чисел в формате с плавающей точкой практически всегда некорректно. Но даже сравнение на неравенство таких чисел нельзя выполнять в случае, когда в точной арифметике эти числа должны быть равны. По этой причине нельзя использовать циклы с вещественным счетчиком в случаях, когда на интервале изменения счетчика укладывается целое число шагов счетчика.
Задания
- Написать приложение с графическим пользовательским интерфейсом, в котором по нажатию на кнопку иллюстрируется действие операторов цикла for , while , do...while – в зависимости от того, какая из кнопок JRadioButton нажата. С помощью этих циклов должна вычисляться площадь под кривой, задаваемой функцией , при x меняющемся от x1 до x2, где величины a,b,c, x1 и x2 должны вводиться пользователем в соответствующих пунктах ввода.
- Добавить в это приложение вычисление с вещественным счетчиком цикла для какого-либо из операторов ( for , while или do...while ) в случае, когда отмечена соответствующая опция с помощью кнопки JCheckBox. Показать наличие неустойчивости при очень малом изменении входных параметров (какой-либо из величин a,b,c, x1,x2 ). Объяснить, почему изменение одних параметров приводит к неустойчивости, а других – нет.
- Написать приложение с графическим пользовательским интерфейсом, в котором по нажатию на кнопку JButton иллюстрируется действие операторов прерывания continue, break, return, System.exit – в зависимости от того, какая из кнопок JToggleButton нажата.