Управляващи оператори - II

** Оператор за цикъл do/while.
Понякога се иска да се изпълни тялото на цикъла най-малко един път и след това да се провери теста за край на цикъла (след като тялото е било изпълнено).
do
{ statements
}
while (condition);
Пример: Древните гърци са използвали прост алгоритъм за пресмятане на корен квадратен:
редицата
  x0 = axn+1 = ( xn + a/xn ) / 2, n = 1, 2, 3, ...
е сходяща и има граница корен квадратен от a.

do
{ xold = xnew;
xnew = (xold + a / xold) / 2;
}
while (fabs(xnew - xold) > EPSILON);

// sqroot.cpp
#include
<iostream> #include <cmath> using namespace std; int main() {  cout << "Please enter a number: ";    double a;    cin >> a;        const double EPSILON = 1E-14;    double xnew = a;    double xold;    do    {  xold = xnew;       xnew = (xold + a / xold) / 2;    }    while (fabs(xnew - xold) > EPSILON);    cout << "The square root is " << xnew << "\n";    return 0; }
Ако един алгоритъм генерира безкрайна редица, то той се нарича итеративен алгоритъм.
В някои случаи редицата от точки е сходяща и границата й е решение на задачата.
Тази програма е нагледна илюстрация на сходимостта на алгоритъма за намиране на квадратен корен за положителни числа.
За положителни стойности на a редицата е сходяща.
За отрицателни a може да се види поведението на получената редица - тя не е сходяща.

** Вложени цикли
Пример: Таблица от стойности с крайна сума за вложени на влог пари с дадена годишна лихва и бой години. 
Таблицата показва съдбата на 10 хиляди щатски долара, инвестирани с различни лихвени проценти за различен брой години.
Псевдокод:
print table header
double rate;
for (rate = RATE_MIN; rate <= RATE_MAX;
rate = rate + RATE_INCR)
{ print table row
}
Хедърът на таблицата също се получава е един цикъл:
cout << "Rate     ";
int year;
for (year = YEAR_MIN; year <= YEAR_MAX;
year = year + YEAR_INCR)
{ cout << setw(2) << year << " years";
}
За отпечатване на един ред се използва още един цикъл - така получаваме вложен цикъл.
// table.cpp
#include
<iostream> #include <iomanip> #include <cmath>
using namespace std;

int main()
{  const double RATE_MIN = 5;
   const double RATE_MAX = 10;
   const double RATE_INCR = 0.5;
   const int YEAR_MIN = 5;
   const int YEAR_MAX = 30;
   const int YEAR_INCR = 5;

   /* print table header */

   cout << " Rate  ";
   int year;
   for (year = YEAR_MIN; year <= YEAR_MAX; 
        year = year + YEAR_INCR)
      cout << setw(2) << year << " years  ";
   cout << "\n";
   cout << fixed << setprecision(2);

   double rate;
   double initial_balance = 10000;
   for (rate = RATE_MIN; rate <= RATE_MAX; 
        rate = rate + RATE_INCR)
   {  
      /* print table row */
       int year;
       cout << setw(5) << rate;
       for (year = YEAR_MIN; year <= YEAR_MAX;
          year = year + YEAR_INCR)
       {  double balance = 
             initial_balance * pow(1 + rate/100, year);
          cout << setw(10) << balance;
       }
       cout << "\n";
   }
   return 0;
}
В някои случаи броят на итерациите (изпълнения на тялото на цикъла) на вътрешния цикъл зависи от броячът на итерациите на външния цикъл.
Пример:  Какво ще отпечати следващата програма?

// triangle.cpp
#include <iostream>
using namespace std;

int main()
{  cout << "Enter number of rows: ";
   int n;
   cin >> n;

   for (int i = 1; i <= n; i++)
   {  for (int j = 1; j <= i; j++) cout << "[]";
      cout << "\n"; 
   }
   return 0;
}

[][][]
[][]
[]


** Четене на данни и пренасочване на входния и изходния потоци
Конструкцията while (cin >> x) чете данни от входа докато не се появи грешка във входния поток.
Грешка във входния поток се появява когато:
-- има несъответствие между типа на променливата x и типа на въведената стойност или
-- когато се въведе специален символ за край на входа (край на файла).
За операционната система Windows този символ е Ctrl-Z (ASCII 26),  за UNIX и MAC OS - Ctrl D (ASCII 04).

Пример: Брой на думите от входния поток.
// words.cpp
#include
<iostream> #include <string> using namespace std; int main() {  int count = 0;    string word;    while (cin >> word) count++;    cout << count << " words." << endl;    return 0; }
* Пренасочване на входа (cin)
    C:\my\>myprog < a_cin.txt
Вместо от клавиатурата, операционната система пренасочва входа от текстов файл, в случая това е файла 
a_cin.txt.
По този начин програмата за намиране на броя на думите може намери броя на думите в текстов файл (едно по-смислено приложение на тази програма).
* Пренасочване на изхода (cout)
    C:\my\>myprog > a_cout.txt 
Вместо на екрана, операционната система пренасочва изхода на текстов файл, в случая това е файла a_cout.txt.

* Четене на редове
Текстови файлове в различни операционни системи - край на ред:
- Unix - LF (Line feed, '\n', 0x0A, 10 in decimal)
- MAC OS - CR (Carriage return, '\r', 0x0D, 13 in decimal)
- Windows - LFCR
Константа endl от потоковата библиотека за извеждане на "край на ред" по стандарта на съответната ОС.
За четене на редове се използва функцията getline.
string line;
while (getline(cin, line))
{ process line
}
Пример: Брой на редовете във входния поток.
// lines.cpp
#include <iostream>
#include <string>
using namespace std;

int main()
{  int count = 0;
   string lines;
   while (getline(cin, lines)) count++;
   cout << count << " lines." << endl;
   return 0;
}

* Четене на символи - букви, цифри и специални символи
За въвеждане на символ по символ (включително малки ASCII кодове) се използва член-функцията get:
char ch;
while (cin.get(ch))
{ process ch
}
Пример: Брой на символите (знаците) във входния поток.
// chars.cpp
#include <iostream>
using namespace std;

int main()
{  int count = 0;
   char ch;
   while (cin.get(ch)) count++;
   cout << count << " chars." << endl;
   return 0;
}

** Симулации
Симулация е решаване на задача с генериране на случайни събития и оценката на техните резултати.
C++ библиотеката разполага с генератор на случайни числа, който произвежда числа, чието поведение прилича на случайно.
Функцията rand() връща случайно число между 0 и RAND_MAX (обикновено 32 767).
Тези числа действителните произхождат от много дълга редица от числа, изчислени от доста прости формули; те просто се държат като случайни числа.
Поради тази причина те често се наричат псевдослучайни числа.
Пример: Следващатата програма произвежда точно същия изход всеки път, когато програмата се изпълнява (защото числата са получени с формула).
int main()
{ int i;
for (i = 1; i <= 10; i++)
{
int r = rand();
cout << r << "\n";
}
return 0;
}
random.cpp

Когато се зададе нова стойност на началото на редицата (seed), ще се получи и друга редица от случайни числа.
За тази цел има функция srand(seed), която променя началото на редицата.
Когато се иска при различни пускания на програмата да се генерират различни числови редици, за параметър на функцията се използва времето от компютърния часовник.
Time now;
int seed = now.seconds_from(Time(0,0,0));
srand(seed);
За генериране на случайни цели числа в интервала  [a, b] се използва следната функция:
int rand_int(int a, int b)
{
return a + rand() % (b - a + 1);
}
Пример: Хвърляне на зарове.
// dice.cpp 
#include
<iostream> #include <string> #include <cstdlib> #include <ctime> using namespace std; /**    Sets the seed of the random number generator. */ void rand_seed() {  int seed = static_cast<int>(time(0));    srand(seed); } /**     Compute a random integer in a range    @param a the bottom of the range    @param b the top of the range    @return a random integer x, a <= x and x <= b */ int rand_int(int a, int b) {  return a + rand() % (b - a + 1); } int main() {  rand_seed();    int i;    for (i = 1; i <= 10; i++)    {  int d1 = rand_int(1, 6);       int d2 = rand_int(1, 6);       cout << d1 << " " << d2 << "\n";    }    cout << "\n";    return 0; }
За генериране на случайни числа тип double в интервала  [a, b]:
double rand_double(double a, double b)
{
return a + (b - a) * rand() * (1.0 / RAND_MAX);
}
Пример: Иглата на Бюфон.
Игла с дължина 1 инч (2.54 см) се пуска върху лист хартия, на който са начертани хоризонтални линии, намиращи се на разстояние 2 инча една от друга. Ако иглата падне върху такава линия, казваме, че имаме попадение.

Хипотезата на Бюфон е, че отношението на броя на всички опити към броя на попаденията клони към числото pi. 
// buffon.cpp 
#include <iostream> 
#include <cstdlib> 
#include <cmath> 
#include <ctime> 
using namespace std;

void rand_seed() 
/* ЦЕЛ: Инициализира генератора за случайни числа 
*/ 
{  int seed = static_cast<int>(time(0)); 
   srand(seed); 
} 
double rand_double(double a, double b) 
/* ЦЕЛ:  намира случайно число в интервала [a, b] 
   ПОЛУЧАВА: границите на интервала 
   ВРЪЩА: случайно число x, a <= x и x <= b 
*/ 
{  return a + (b - a)*rand()*(1.0/RAND_MAX); 
} 
double deg2rad(double alpha) 
/* ЦЕЛ:  превръща градуси в радиани 
   ПОЛУЧАВА: alpha - големина на ъгъл в градуси 
   ВРЪЩА:  големината на ъгъла в радиани 
*/ 
{  const double PI = 3.141592653589793; 
   return alpha * PI / 180; 
} 
int main() 
{  int NTRIES = 10000; 
   int i; 
   int hits = 0; 
   rand_seed(); 
   for (i = 1; i <= NTRIES; i++) 
   {  double ylow = rand_double(0, 2); 
      double angle = rand_double(0, 180); 
      double yhigh = ylow + sin(deg2rad(angle)); 
      if (yhigh >= 2) hits++; 
   } 
   cout << "Tries / Hits = " << NTRIES*(1.0/hits) << "\n"; 
   return 0; 
}

Смисълът на тази програма е не да се изчисли пи (в края на краищата, трябваше да се използва стойността на пи във функцията deg2rad).
Въпросът е да покаже как физичен експеримент може да се симулира на компютъра.