Функции 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() используются для округления сумм до центов, а также для расчета налогов и скидок. В разработке игр они используются для позиционирования объектов в сетке. Также, функции могут использоваться для создания пользовательских функций округления и для работы с временными интервалами. Важно помнить, что эти функции работают с числами с плавающей точкой, и при их использовании необходимо учитывать возможные проблемы точности.