Remove the "Лог файл" (Log file) column from the report generation as it's no longer needed. This simplifies the report structure and removes unused functionality.
3 lines
11 KiB
Plaintext
3 lines
11 KiB
Plaintext
Функции floor() и ceil() на C++ занимаются не только округлением чисел. Изучим их эффективное использование в реальных сценариях — от финансовых расчетов до разработки игр. Базовое применение floor() и ceil() Сначала посмотрим на эти функции в деле: #include <cmath> #include <iostream> void basic_examples() { double numbers[] = {3.7, -3.7, 0.0, -0.0, 3.0, -3.0}; for (double num : numbers) { std::cout << "Number: " << num << '\n' << "Floor: " << std::floor(num) << '\n' << "Ceil: " << std::ceil(num) << '\n' << "-------------------\n"; } } // Вывод: // Число: 3.7 // Пол: 3 // Потолок: 4 // ------------------- // Число: -3.7 // Пол: -4 // Потолок: -3 // ------------------- // ... и так далее Реальный пример: финансовые расчеты Вот как используются floor() и ceil() для финансового округления: class MoneyCalculator { public: // Округляется до цента static double round_currency(double amount) { return std::floor(amount * 100 + 0.5) / 100; } // Округляются вверх до цента, например комиссии static double ceil_currency(double amount) { return std::ceil(amount * 100) / 100; } // Округляются вниз до цента, например дисконт static double floor_currency(double amount) { return std::floor(amount * 100) / 100; } }; void financial_example() { double price = 19.999; double tax_rate = 0.08; // 8%-ный налог double tax = MoneyCalculator::ceil_currency(price * tax_rate); double final_price = MoneyCalculator::round_currency(price + tax); std::cout << "Original price: $" << price << '\n' << "Tax: $" << tax << '\n' << "Final price: $" << final_price << '\n'; } Разработка игр: сеточное позиционирование Вот как floor() и ceil() используются в сеточной игровой механике: struct Vector2D { double x, y; Vector2D(double x_, double y_) : x(x_), y(y_) {} }; class GridSystem { public: static constexpr double CELL_SIZE = 64.0; // пиксели static Vector2D world_to_grid(const Vector2D& world_pos) { return Vector2D( std::floor(world_pos.x / CELL_SIZE), std::floor(world_pos.y / CELL_SIZE) ); } static Vector2D grid_to_world(const Vector2D& grid_pos) { return Vector2D( grid_pos.x * CELL_SIZE, grid_pos.y * CELL_SIZE ); } static Vector2D snap_to_grid(const Vector2D& world_pos) { Vector2D grid_pos = world_to_grid(world_pos); return grid_to_world(grid_pos); } }; void game_example() { Vector2D player_pos(123.45, 67.89); Vector2D grid_pos = GridSystem::world_to_grid(player_pos); Vector2D snapped_pos = GridSystem::snap_to_grid(player_pos); std::cout << "Player position: (" << player_pos.x << ", " << player_pos.y << ")\n" << "Grid position: (" << grid_pos.x << ", " << grid_pos.y << ")\n" << "Snapped position: (" << snapped_pos.x << ", " << snapped_pos.y << ")\n"; } Пользовательские функции округления Вот набор полезных утилит округления: class RoundingUtils { public: // Округляются до ближайшего кратного static double round_to_multiple(double value, double multiple) { return std::floor(value / multiple + 0.5) * multiple; } // Округляются вверх до ближайшего кратного static double ceil_to_multiple(double value, double multiple) { return std::ceil(value / multiple) * multiple; } // Округляются вниз до ближайшего кратного static double floor_to_multiple(double value, double multiple) { return std::floor(value / multiple) * multiple; } // Округляются до указанных знаков после запятой static double round_to_decimal(double value, int decimal_places) { double multiplier = std::pow(10.0, decimal_places); return std::floor(value * multiplier + 0.5) / multiplier; } }; void demonstrate_rounding() { double value = 47.123; std::cout << "Original value: " << value << '\n' << "Rounded to nearest 5: " << RoundingUtils::round_to_multiple(value, 5.0) << '\n' << "Ceiling to nearest 5: " << RoundingUtils::ceil_to_multiple(value, 5.0) << '\n' << "Floor to nearest 5: " << RoundingUtils::floor_to_multiple(value, 5.0) << '\n' << "Rounded to 2 decimals: " << RoundingUtils::round_to_decimal(value, 2) << '\n'; } Пример распределения ресурсов Вот как при помощи ceil() рассчитывается выделение памяти: class ResourceAllocator { public: static constexpr size_t BLOCK_SIZE = 4096; // Блоки 4 Кб static size_t calculate_blocks_needed(size_t bytes) { return static_cast<size_t>(std::ceil(static_cast<double>(bytes) / BLOCK_SIZE)); } static size_t calculate_allocation_size(size_t bytes) { return calculate_blocks_needed(bytes) * BLOCK_SIZE; } static void print_allocation_info(size_t requested_bytes) { size_t blocks = calculate_blocks_needed(requested_bytes); size_t actual_bytes = calculate_allocation_size(requested_bytes); std::cout << "Requested: " << requested_bytes << " bytes\n" << "Blocks needed: " << blocks << '\n' << "Actual allocation: " << actual_bytes << " bytes\n" << "Wasted space: " << actual_bytes - requested_bytes << " bytes\n"; } }; void allocation_example() { ResourceAllocator::print_allocation_info(6000); // Больше, чем один блок ResourceAllocator::print_allocation_info(2048); // Меньше, чем один блок } Работа с временными интервалами А так floor() и ceil() справляются с вычислениями времени: class TimeCalculator { public: static constexpr int SECONDS_PER_MINUTE = 60; static constexpr int SECONDS_PER_HOUR = 3600; static int ceil_minutes(double seconds) { return static_cast<int>(std::ceil(seconds / SECONDS_PER_MINUTE)); } static int floor_minutes(double seconds) { return static_cast<int>(std::floor(seconds / SECONDS_PER_MINUTE)); } static std::string format_time_range(double seconds) { int min_minutes = floor_minutes(seconds); int max_minutes = ceil_minutes(seconds); if (min_minutes == max_minutes) { return std::to_string(min_minutes) + " minutes"; } return std::to_string(min_minutes) + "-" + std::to_string(max_minutes) + " minutes"; } static int calculate_billing_units(double hours, double unit_size = 0.25) { return static_cast<int>(std::ceil(hours / unit_size)); } }; void time_example() { double task_duration = 127.5; // секунды std::cout << "Task will take: " << TimeCalculator::format_time_range(task_duration) << '\n'; double meeting_hours = 1.6; // один час 36 минут int billing_units = TimeCalculator::calculate_billing_units(meeting_hours); std::cout << "Billable units (15-minute intervals): " << billing_units << '\n'; } Типичные проблемы и их решения Проблемы точности вычислений с плавающей точкой: double value = 2.0; // Не делайте этого: if (std::floor(value) == value) { // Не выполнится из-за точности std::cout << "Integer value\n"; } // Делайте так: const double epsilon = 1e-10; if (std::abs(std::floor(value) - value) < epsilon) { std::cout << "Integer value\n"; } 2. Целочисленное переполнение при приведении типов: class SafeRounding { public: static int safe_floor(double value) { if (value > std::numeric_limits<int>::max() || value < std::numeric_limits<int>::min()) { throw std::overflow_error("Value out of integer range"); } return static_cast<int>(std::floor(value)); } }; Не забывайте, что floor() и ceil() предназначены для типов с плавающей точкой float, double, long double. Для целочисленных типов эти операции излишни, поскольку целые числа уже «округлены» по определению. Читайте также: C++: полное руководство по вставке в векторах C++: полное руководство по std::stoi C++: полное руководство по динамическим массивам Читайте нас в Telegram, VK и Дзен Перевод статьи ryan: Floor and Ceil Functions in C++: Complete Guide
|
||
==============
|
||
Функции floor() и ceil() в C++ используются для округления чисел до ближайшего целого числа. floor() возвращает наибольшее целое число, которое меньше или равно заданному, а ceil() возвращает наименьшее целое число, которое больше или равно заданному. Эти функции полезны во многих сценариях, таких как финансовые расчеты, разработка игр и обработка данных. В финансовых расчетах floor() и ceil() используются для округления сумм до центов, а также для расчета налогов и скидок. В разработке игр они используются для позиционирования объектов в сетке. Также, функции могут использоваться для создания пользовательских функций округления и для работы с временными интервалами. Важно помнить, что эти функции работают с числами с плавающей точкой, и при их использовании необходимо учитывать возможные проблемы точности. |