» » » » Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

На нашем литературном портале можно бесплатно читать книгу Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп, Бьёрн Страуструп . Жанр: Программирование. Онлайн библиотека дает возможность прочитать весь текст и даже без регистрации и СМС подтверждения на нашем литературном портале litmir.org.
Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп
Название: Программирование. Принципы и практика использования C++ Исправленное издание
Дата добавления: 22 август 2024
Количество просмотров: 100
Читать онлайн

Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних просмотр данного контента СТРОГО ЗАПРЕЩЕН! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту readbookfedya@gmail.com для удаления материала

Программирование. Принципы и практика использования C++ Исправленное издание читать книгу онлайн

Программирование. Принципы и практика использования C++ Исправленное издание - читать бесплатно онлайн , автор Бьёрн Страуструп

Специальное издание самой читаемой и содержащей наиболее достоверные сведения книги по C++. Книга написана Бьярне Страуструпом — автором языка программирования C++ — и является каноническим изложением возможностей этого языка.
Помимо подробного описания собственно языка, на страницах книги вы найдете доказавшие свою эффективность подходы к решению разнообразных задач проектирования и программирования. Многочисленные примеры демонстрируют как хороший стиль программирования на С-совместимом ядре C++, так и современный -ориентированный подход к созданию программных продуктов. Третье издание бестселлера было существенно переработано автором. Результатом этой переработки стала большая доступность книги для новичков. В то же время, текст обогатился сведениями и методиками программирования, которые могут оказаться полезными даже для многоопытных специалистов по C++. Не обойдены вниманием и нововведения языка: стандартная библиотека шаблонов (STL), пространства имен (namespaces), механизм идентификации типов во время выполнения (RTTI), явные приведения типов (cast-операторы) и другие.
Настоящее специальное издание отличается от третьего добавлением двух новых приложений (посвященных локализации и безопасной обработке исключений средствами стандартной библиотеки), довольно многочисленными уточнениями в остальном тексте, а также исправлением множества опечаток.
Книга адресована программистам, использующим в своей повседневной работе C++. Она также будет полезна преподавателям, студентам и всем, кто хочет ознакомиться с описанием языка «из первых рук».

Перейти на страницу:
зрения красоты стиля этого лучше не делать, а задать их все с помощью одной функции.

void Axis::set_color(Color c)

{

  Shape::set_color(c);

  notches.set_color(c);

  label.set_color(c);

}

Аналогично, функция Axis::move() перемещает все три части объекта класса Axis одновременно.

void Axis::move(int dx, int dy)

{

  Shape::move(dx,dy);

  notches.move(dx,dy);

  label.move(dx,dy);

15.5. Аппроксимация

Рассмотрим еще один небольшой пример построения графика функции: “анимируем” вычисление экспоненты. Наша цель — дать вам почувствовать математические функции, продемонстрировать применение графиков для иллюстрации вычислений, показать фрагменты кода и, в заключение, предупредить о типичных проблемах, связанных с вычислениями.

Один из способов вычисления экспоненты сводится к суммированию степенного ряда.

ex = 1 + x + x2/2! + x3/3! + x4/4! + ...

Чем больше членов ряда мы вычислим, тем точнее будет значение ex; иначе говоря, чем больше членов ряда мы вычисляем, тем больше правильных цифр найдем в результате. В программе мы суммируем ряд и строим график его частичных сумм. В этой формуле знак восклицания, как обычно, обозначает факториал, т.е. мы строим графики функций в следующем порядке:

exp0(x) = 0   // нет членов

exp1(x) = 1   // один член

exp2(x) = 1+x // два члена ; pow(x,1)/fac(1)==x

exp3(x) = 1+x+pow(x,2)/fac(2)

exp4(x) = 1+x+pow(x,2)/fac(2)+pow(x,3)/fac(3)

exp5(x) = 1+x+pow(x,2)/fac(2)+pow(x,3)/fac(3)+pow(x,4)/fac(4)

...

Каждая функция немного точнее приближает ex, чем предыдущая. Здесь pow(x,n) — стандартная библиотечная функция, возвращающая xn. В стандартной библиотеке нет функции, вычисляющей факториал, поэтому мы должны определить ее самостоятельно.

int fac(int n) // factorial(n); n!

{

  int r = 1;

  while (n>1) {

    r*=n;

    ––n;

  }

  return r;

}

Альтернативная реализация функции fac() описана в упр. 1. Имея функцию fac(), можем вычислить n-й член ряда.

double term(double x, int n) { return pow(x,n)/fac(n); } // n-й

                                                         // член ряда

Имея функцию term(), несложно вычислить экспоненты с точностью до n членов.

double expe(double x, int n) // сумма n членов для x

{

  double sum = 0;

  for (int i=0; i<n; ++i) sum+=term(x,i);

  return sum;

}

Как построить график этой функции? С точки зрения программиста трудность заключается в том, что наш класс Function получает имя функции одного аргумента, а функция expe() имеет два аргумента. В языке С++ нет элегантного решения этой задачи, поэтому пока воспользуемся неэлегантным решением (тем не менее, см. упр. 3). Мы можем удалить точность n из списка аргументов и сделать ее переменной.

int expN_number_of_terms = 10;

double expN(double x)

{

  return expe(x,expN_number_of_terms);

}

Теперь функция expN(x) вычисляет экспоненту с точностью, определенной значением переменной expN_number_of_terms. Воспользуемся этим для построения нескольких графиков. Сначала построим оси и нарисуем истинный график экспоненты, используя стандартную библиотечную функцию exp(), чтобы увидеть, насколько хорошо она приближается функцией expN().

Function real_exp(exp,r_min,r_max,orig,200,x_scale,y_scale);

real_exp.set_color(Color::blue);

Затем выполним цикл приближений, увеличивая количество членов ряда n.

for (int n = 0; n<50; ++n) {

  ostringstream ss;

  ss << " приближение exp; n==" << n ;

  win.set_label(ss.str());

  expN_number_of_terms = n;

  // следующее приближение:

  Function e(expN,r_min,r_max,orig,200,x_scale,y_scale);

  win.attach(e);

  win.wait_for_button();

  win.detach(e);

}

Обратите внимание на последний вызов detach(e) в этом цикле. Область видимости объекта e класса Function ограничена телом цикла for. Каждый раз, кода мы входим в этот блок, мы создаем новый объект e класса Function, а каждый раз, когда выходим из блока, объект e уничтожается и затем заменяется новым. Объект класса Window не должен помнить о старом объекте e, потому что он будет уничтожен. Следовательно, вызов detach(e) гарантирует, что объект класса Window не попытается нарисовать разрушенный объект.

На первом этапе мы получаем окно, в котором нарисованы оси и “настоящая” экспонента (синий цвет).

Как видим, значение exp(0) равно 1, поэтому наш синий график “настоящей” экспоненты пересекает ось y в точке (0,1). Если присмотреться повнимательнее, то видно, что на самом деле мы нарисовали первое приближение (exp0(x)==0) черным цветом поверх оси x. Кнопка Next позволяет получить аппроксимацию, содержащую один член степенного ряда. Обратите внимание на то, что мы показываем количество сленгов ряда, использованного для приближения экспоненты, как часть метки окна.

Это функция exp1(x)==1, представляющая собой аппроксимацию экспоненты с помощью только одного члена степенного ряда. Она точно совпадает с экспонентой в точке (0,1), но мы можем построить более точную аппроксимацию.

Используя два члена разложения (1+x), получаем диагональ, пересекающую ось y в точке (0,1). С помощью трех членов разложения (1+x+pow(x,2)/fac(2)) можем обнаружить признаки сходимости.

Десять членов приближения дают очень хорошее приближение, особенно для значений x, превышающих –3.

На первый взгляд, мы могли бы получать все более точные аппроксимации, постоянно увеличивая количество членов степенного ряда. Однако существует предел, и после тринадцати членов происходит нечто странное: аппроксимация ухудшается, а после вычисления восемнадцати членов на рисунке появляются вертикальные линии.

 

 Помните, что арифметика чисел с плавающей точкой — это не чистая математика. Числа с плавающей точкой просто хорошо приближают действительные числа, поскольку для их представления можно использовать лишь ограниченное количество бит. С определенного момента наши вычисления стали порождать числа, которые невозможно точно представить в виде переменных типа double, и наши результаты стали отклоняться от правильного ответа. Более подробная информация на эту тему приведена в главе 24.

Последний рисунок представляет собой хорошую иллюстрацию следующего принципа: если ответ выглядит хорошо, еще не значит, что программа работает правильно. Если программа проработает немного дольше или на несколько других данных, то может возникнуть

Перейти на страницу:
Комментариев (0)