当前位置: 首页 > news >正文

C++ round 函数笔记 (适用于算法竞赛)

在算法竞赛中,处理浮点数并将其转换为整数是常见的需求,round 函数是标准库提供的用于执行“四舍五入”到最近整数的工具。理解其工作方式和潜在问题对于避免错误至关重要。

1. 基本用法

头文件

要使用 round 函数,需要包含 <cmath> 头文件 (C++ 风格) 或 <math.h> (C 风格)。推荐使用 <cmath>

#include <cmath>
#include <iostream>int main() {double num1 = 3.14;double num2 = 3.75;double num3 = -2.3;double num4 = -2.8;double num5 = 4.5;double num6 = -4.5;std::cout << "round(" << num1 << ") = " << std::round(num1) << std::endl; // 输出 3.0std::cout << "round(" << num2 << ") = " << std::round(num2) << std::endl; // 输出 4.0std::cout << "round(" << num3 << ") = " << std::round(num3) << std::endl; // 输出 -2.0std::cout << "round(" << num4 << ") = " << std::round(num4) << std::endl; // 输出 -3.0std::cout << "round(" << num5 << ") = " << std::round(num5) << std::endl; // 输出 5.0std::cout << "round(" << num6 << ") = " << std::round(num6) << std::endl; // 输出 -5.0return 0;
}

函数签名

round 函数有多个重载版本,接受不同的浮点类型:

double round(double x);
float roundf(float x);       // C++11 起通常也有 round(float)
long double roundl(long double x); // C++11 起通常也有 round(long double)

在 C++ 中,通常可以直接使用 std::round(),编译器会根据参数类型自动选择合适的版本。

2. 核心规则:四舍五入到最近整数

round 函数将浮点数 x 舍入到最接近的整数值。

关键点:中间值处理 (Handling Halves)

  • 当小数部分恰好为 0.5 时,round 函数遵循**“远离零”**的原则进行舍入。
    • round(2.5) 结果是 3.0
    • round(-2.5) 结果是 -3.0
  • 这与某些其他编程语言或场景下的“四舍五入到偶数”(Round half to even / Banker’s rounding)不同。

3. 返回值类型

非常重要: round 函数的返回值类型仍然是浮点类型 (double, float, long double),即使它表示的是一个整数值。

如果你需要一个真正的整数类型 (int, long long 等),你需要进行显式类型转换

#include <cmath>
#include <iostream>int main() {double val = 9.8;double rounded_val_double = std::round(val); // rounded_val_double 是 10.0 (double类型)// 显式转换为整数类型int rounded_val_int = static_cast<int>(rounded_val_double);       // 推荐的C++风格转换long long rounded_val_ll = static_cast<long long>(std::round(1e10 + 0.3)); // 处理可能较大的数std::cout << "Rounded (double): " << rounded_val_double << std::endl;std::cout << "Rounded (int): " << rounded_val_int << std::endl;std::cout << "Rounded (long long): " << rounded_val_ll << std::endl; // 输出 10000000000// 注意潜在的溢出问题double large_val = 3e9; // 3 * 10^9int overflow_int = static_cast<int>(std::round(large_val));// 上一行可能导致整数溢出,结果未定义或取决于实现std::cout << "Potential overflow: " << overflow_int << std::endl;return 0;
}

4. 注意事项与竞赛技巧

a. 浮点数精度问题 (Floating-Point Precision Issues)

  • 这是在算法竞赛中使用浮点数(包括 round)时最需要注意的问题。
  • 计算机存储浮点数存在误差。一个看似是 x.5 的数,在内存中可能是 x.4999999999999999x.5000000000000001
  • 这会导致 round 的结果与预期不符。例如,你期望 round(a / b * c) 得到某个整数,但由于中间计算的精度损失,结果可能差一点点,导致 round 结果错误。

竞赛建议:

  1. 尽量避免浮点数: 如果问题可以通过全程使用整数算术解决,优先选择整数。例如,比较 a/bc/d 时,转换为比较 a*dc*b (注意溢出)。
  2. 使用 Epsilon (eps): 在判断浮点数相等或比较大小时,引入一个极小值 eps (如 1e-81e-9)。例如,判断 x 是否接近整数 n,可以用 fabs(x - n) < eps
  3. 谨慎使用 round 只有在确实需要四舍五入,并且能接受微小误差带来的潜在风险时使用。

b. 手动实现整数“四舍五入”

有时,为了完全避免浮点误差,或者需要对整数运算结果进行类似四舍五入的操作,可以手动实现:

  • 对于非负数 x (int)(x + 0.5)(long long)(x + 0.5)
  • 对于负数 x (int)(x - 0.5)(long long)(x - 0.5)
#include <iostream>
#include <vector> // 仅用于演示// 简化的手动四舍五入到整数 (int)
int manual_round_int(double x) {if (x >= 0.0) {return static_cast<int>(x + 0.5);} else {return static_cast<int>(x - 0.5);}
}// 更通用的手动四舍五入到长整型 (long long)
long long manual_round_ll(double x) {if (x >= 0.0) {return static_cast<long long>(x + 0.5);} else {return static_cast<long long>(x - 0.5);}
}int main() {std::cout << "Manual round(3.7): " << manual_round_int(3.7) << std::endl;   // 4std::cout << "Manual round(3.2): " << manual_round_int(3.2) << std::endl;   // 3std::cout << "Manual round(3.5): " << manual_round_int(3.5) << std::endl;   // 4std::cout << "Manual round(-3.7): " << manual_round_int(-3.7) << std::endl; // -4std::cout << "Manual round(-3.2): " << manual_round_int(-3.2) << std::endl; // -3std::cout << "Manual round(-3.5): " << manual_round_int(-3.5) << std::endl; // -4// 示例:整数除法的四舍五入int a = 10, b = 3;// int result = a / b; // 结果是 3 (整数截断)// 要实现 a/b 的四舍五入结果:int rounded_div = static_cast<int>(static_cast<double>(a) / b + 0.5); // 先转double再加0.5// 或者,更推荐的整数算术方法(避免浮点):// rounded_div = (a + b / 2) / b; // 对于正数 a, bstd::cout << "Rounded division 10/3: " << rounded_div << std::endl; // 输出 3 (这里10/3=3.33, round是3)a = 11; b = 3; // 11/3 = 3.66...rounded_div = static_cast<int>(static_cast<double>(a) / b + 0.5);std::cout << "Rounded division 11/3: " << rounded_div << std::endl; // 输出 4return 0;
}

注意: 手动加 0.5 的方法仍然依赖于浮点数 x 的精度。如果 x 本身由于计算误差变成了 y.49999...x + 0.5 可能会小于 y + 1.0,导致转换后仍为 y 而不是预期的 y+1。只有当你知道输入 x 是精确的,或者这种微小误差不影响结果时,它才是可靠的。

c. 考虑 ceil, floor, trunc

<cmath> 还提供了其他相关的取整函数:

  • ceil(x): 向上取整 (Ceiling)。返回 >= x 的最小整数值 (仍为浮点类型)。
  • floor(x): 向下取整 (Floor)。返回 <= x 的最大整数值 (仍为浮点类型)。
  • trunc(x): 向零取整 (Truncate)。直接截断小数部分,取整数部分 (仍为浮点类型)。等价于 (double)((int)x) (如果 xint 范围内且非负)。

根据具体需求选择合适的函数。

d. 输出格式化

有时,你可能只是为了输出一个四舍五入的整数,并不需要在程序内部使用这个整数值。可以使用 printf 的格式化功能:

#include <cstdio> // for printf
#include <cmath>int main() {double val = 9.8;double val2 = 9.4;double val3 = -9.8;printf("%.0f\n", val);  // 输出 10 (%.0f 通常执行四舍五入,规则类似 round)printf("%.0f\n", val2); // 输出 9printf("%.0f\n", val3); // 输出 -10return 0;
}

注意: printf%.0f 的具体舍入规则(尤其是对 0.5 的处理)可能依赖于 C++ 标准库的实现,但通常是“远离零”。最好通过测试确认。

5. 总结

  • std::round 用于将浮点数四舍五入到最接近的整数(中间值 0.5 远离零),返回浮点类型
  • 在竞赛中要高度警惕浮点数精度问题round 结果的影响。
  • 如果需要整数结果,必须进行显式类型转换 (static_cast<int>, static_cast<long long>),并注意溢出
  • 优先考虑全程整数算术,如果可能的话。
  • 了解 ceil, floor, trunc 作为替代方案。
  • 了解 printf("%.0f") 可以用于格式化输出。
  • 手动实现 (int)(x + 0.5) (非负) / (int)(x - 0.5) (负) 是避免调用库函数的一种方式,但仍受输入 x 精度影响。

在竞赛中,选择哪种方法取决于问题的具体要求、数据范围以及对精度的要求。理解各种方法的优缺点和潜在陷阱是取得好成绩的关键。

相关文章:

  • Spring Boot实战(三十六)编写单元测试
  • matlab 绘图
  • 手搓雷达图(MATLAB)
  • 网络安全 | F5 WAF 黑白名单配置实践指南
  • ArcGIS Pro跨图层复制粘贴
  • 第十三届蓝桥杯 2022 C/C++组 修剪灌木
  • 抖音的逆向工程获取弹幕(websocket和protobuf解析)
  • 【QT网络】构建简单Udp回显服务器
  • Flutter Dart 循环语句 for while do..while break、continue
  • CGAL 网格内部生成随机点
  • 图论---朴素Prim(稠密图)
  • Linux内核netlink机制 - 连接器(Netlink Connector)
  • 解决cannot find attribute `serde` in this scope记录
  • 远程访问服务器的Jupyter Notebook
  • 生成随机验证码-解析与优化
  • 代码随想录算法训练营第一天:数组part1
  • 第六章 QT基础:6、QT的Qt 时钟编程
  • 协作开发攻略:Git全面使用指南 — 第三部分 特殊应用场景
  • JW01三合一传感器详解(STM32)
  • 深度剖析操作系统核心(第一节):从X86/ARM/MIPS处理器架构到虚拟内存、分段分页、Linux内存管理,再揭秘进程线程限制与优化秘籍,助你成为OS高手!
  • 远程控制、窃密、挖矿!我国境内捕获“银狐”木马病毒变种
  • 审议民营经济促进法草案等,十四届全国人大常委会第十五次会议将举行
  • 临汾攻坚PM2.5:一座曾经“爆表”城市的空气治理探索
  • 集合多家“最美书店”,松江成立书店联盟“书香满云间”
  • 纳斯达克中国金龙指数涨2.93%,金价油价大幅下挫
  • 最大涨幅9800%!金价新高不断,引发期权“末日轮”效应,沪金期权多张合约大涨