break;
default:
assert(!"impossible case: 3 or more roots"); // невозможный случай
cout << "unknown error\n";
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}
0460-solve_transcend_0.cpp
// solve_transcend_0.cpp
#include
#include
#include
#include // assert
using namespace std;
// Особое значение "бесконечное количество корней".
const int INFINITE_ROOTS = -1;
const double // Вспомогательные числовые константы
HALF_PI = 1.570796326795, // половина пи
TOLERANCE = 1e-10; // граница между "нулём" и "ненулём"
// Логарифм по произвольному основанию.
double log(double base, double arg)
{
return log(arg) / log(base);
}
// Проверка значения на близость нулю.
bool is_almost_zero(double x, double tolerance = TOLERANCE)
{
return abs(x) <= tolerance;
}
// Левая часть уравнения.
double f(double a, double b, double c, double x)
{
return 1.0 + sin(pow(a, x) + abs(log(b, c)));
}
// Решаем уравнение f(a, b, c, root) = 0 относительно root.
// Функция возвращает "количество корней",
// один корень записывает по ссылке.
int solve_f(double a, double b, double c, double &root)
{
if (a < 0.0 || b <= 0.0 || b == 1.0 || c <= 0.0)
return 0; // нет корней
if (a == 0.0 || a == 1.0) // потенциально почти все возможные x -- корни
return is_almost_zero(f(a, b, c, 1.0))? INFINITE_ROOTS: 0;
// Счётное число корней, вернём один из них (он может не существовать).
root = log(a, 3.0 * HALF_PI - abs(log(b, c)));
return 1;
}
int main()
{
cout << "Solving f(a, b, c, x) = 0, enter a, b, c:\n";
cout.precision(16);
for (double a, b, c, x; cin >> a >> b >> c;)
{
switch (solve_f(a, b, c, x))
{
case 0:
cout << "no roots\n";
break;
case INFINITE_ROOTS:
cout << "any number is a root\n";
break;
case 1: // один корень, записан в x
cout << "x == " << x << ", error is " << f(a, b, c, x) << endl;
break;
default:
assert(!"impossible case: invalid roots quantity"); // невозможный случай
cout << "unknown error\n";
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}
0470-solve_transcend.cpp
// solve_transcend.cpp
#include
#include
#include
#include // assert
using namespace std;
// Особое значение "бесконечное количество корней".
const int INFINITE_ROOTS = -1;
const double // Вспомогательные числовые константы
HALF_PI = 1.5707963267949, // половина пи
PI = 3.14159265358979, // число пи
DOUBLE_PI = 6.2831853071796, // два пи
TOLERANCE = 1e-10; // граница между "нулём" и "ненулём"
// Логарифм по произвольному основанию.
double log(double base, double arg)
{
return log(arg) / log(base);
}
// Проверка значения на близость нулю.
bool is_almost_zero(double x, double tolerance = TOLERANCE)
{
return abs(x) <= tolerance;
}
// Левая часть уравнения.
double f(double a, double b, double c, double x)
{
return 1.0 + sin(pow(a, x) + abs(log(b, c)));
}
// Решаем уравнение f(a, b, c, root) = 0 относительно root.
// Функция возвращает "количество корней",
// один корень записывает по ссылке.
int solve_f(double a, double b, double c, double &root)
{
if (a < 0.0 || b <= 0.0 || b == 1.0 || c <= 0.0)
return 0; // нет корней
if (a == 0.0 || a == 1.0) // потенциально почти все возможные x -- корни
return is_almost_zero(f(a, b, c, 1.0))? INFINITE_ROOTS: 0;
// Счётное число корней, получим один из них.
const double
expr_part = abs(log(b, c)) + HALF_PI, // часть выражения
n = 1.0 + ceil(expr_part / DOUBLE_PI), // номер корня
log_arg = DOUBLE_PI * n - expr_part; // аргумент логарифма в формуле корня
assert(log_arg > 0.0); // всегда должен быть положительным по построению
root = log(a, log_arg);
return 1;
}
int main()
{
cout << "Solving f(a, b, c, x) = 0, enter a, b, c:\n";
cout.precision(16);
for (double a, b, c, x; cin >> a >> b >> c;)
{
switch (solve_f(a, b, c, x))
{
case 0:
cout << "no roots\n";
break;
case INFINITE_ROOTS:
cout << "any number is a root\n";
break;
case 1: // один корень, записан в x
cout << "x == " << x << ", error is " << f(a, b, c, x) << endl;
break;
default:
assert(!"impossible case: invalid roots quantity"); // невозможный случай
cout << "unknown error\n";
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}
0499-array_initialization.cpp
// array_initialization.cpp
// Примеры инициализации одномерных статических массивов.
#include
using namespace std;
// Макрос для "распечатки" статического массива.
#define PRINTA(a) \
for (auto item: a) \
cout << item << ' '; \
cout << endl
int main()
{
// Указан и размер и значения всех элементов.
int xyz[3] = { 1, 2, 3 };
PRINTA(xyz);
// Последние три элемента будут нули.
int zero_tail[6] = { 7, 7, 7 };
PRINTA(zero_tail);
// Типичная инициализация локального массива нулями.
float zeroes[10] = {};
PRINTA(zeroes);
// Размер не указан, определяется количеством значений в инициализаторе.
char word[] = { 'w', 'o', 'r', 'd' };
PRINTA(word);
// В качестве инициализатора можно использовать строковый литерал.
// В конце добавляется нулевой символ, поэтому размер greets 11, а не 10.
char greets[] = "greetings!";
PRINTA(greets) << sizeof(greets) << '\n';
greets[3] = 'a';
cout << greets << endl;
}
0500-positives_negatives.cpp
// positives_negatives.cpp
// Отношение количества положительных к количеству отрицательных элементов.
// Пример: { 4, 1, 100, 0, 20, 0, -1, -2, 3, -6 } -> 5/3 = 1.6666667.
#include
#include
using namespace std;
// П.1: обработка произвольного массива, переданного как адрес + размер,
// size_t -- стандартный тип (определён в Стандартной библиотеке C),
// предназначенный для хранения размеров массивов.
double pn_ratio(const double numbers[], size_t n)
{
// Счётчики положительных и отрицательных чисел.
size_t positives = 0, negatives = 0;
for (size_t i = 0; i < n; ++i)
{
// Ключевое слово auto предписывает компилятору вывести тип переменной
// автоматически по типу инициализирующего выражения.
const auto x = numbers[i]; // следующий элемент последовательности
if (x < 0.0)
++negatives;
else if (x > 0.0)
++positives;
}
// Без приведения к double будет деление в целых числах.
return double(positives) / negatives;
}
// П.2: тестирование функции из п.1 на заранее заданных массивах.
bool test_pn_ratio()
{
const double test1[] = { 4, 1, 100, 0, 20, 0, -1, -2, 3, -6 };
// sizeof возвращает размер статического массива в байтах
// (!) при этом массив должен быть виден в данном контексте непосредственно,
// (!) иначе программист рискует получить вместо размера массива размер указателя на него
if (pn_ratio(test1, sizeof(test1) / sizeof(double)) != 5.0 / 3.0)
return false;
const double test2[] = { -40, -2, -111, 42, 0, 0, 2, -1000, -4 };
if (pn_ratio(test2, sizeof(test2) / sizeof(double)) != 2.0 / 5.0)
return false;
// Все проверки прошли успешно.
return true;
}
// П.3: считывание чисел с потока ввода.
double pn_ratio(istream &in)
{
// Счётчики положительных и отрицательных чисел.
size_t positives = 0, negatives = 0;
for (double x; in >> x;)
{
if (x < 0.0)
++negatives;
else if (x > 0.0)
++positives;
}
// Без приведения к double будет деление в целых числах.
return double(positives) / negatives;
}
int main()
{
// Тестирование варианта обработки данных для массива.
cout << test_pn_ratio() << endl;
// Вариант для обработки данных с потока ввода.
const auto result = pn_ratio(cin);
cout << "\nResult: " << result << endl;
return EXIT_SUCCESS;
}
0501-positives_negatives_2.cpp
// positives_negatives_2.cpp
// Отношение количества положительных к количеству отрицательных элементов.
// Пример: { 4, 1, 100, 0, 20, 0, -1, -2, 3, -6 } -> 5/3 = 1.6666667.
#include
#include
using namespace std;
// П.1: обработка произвольного массива, переданного как адрес + размер,
// size_t -- стандартный тип (определён в Стандартной библиотеке C),
// предназначенный для хранения размеров массивов.
double pn_ratio(const double numbers[], size_t n)
{
// Счётчики положительных и отрицательных чисел.
size_t positives = 0, negatives = 0;
for (size_t i = 0; i < n; ++i)
{
// Ключевое слово auto предписывает компилятору вывести тип переменной
// автоматически по типу инициализирующего выражения.
const
Do'stlaringiz bilan baham: |