news 2026/9/1 23:38:01

std::numeric_limits<float>:一段深夜调试的浮点数探险

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
std::numeric_limits<float>:一段深夜调试的浮点数探险

上周在折腾一个数值计算的小项目,需要用到浮点数的极值判断。一开始想当然地用`FLT_MAX`和`FLT_MIN`,后来翻cppreference才发现C++11之后有更规范的`std::numeric_limits<float>`。正好手头有台阿贝云的免费云服务器,想着干脆在这上面写个测试程序把所有属性打印出来看看。

先写了个简单的demo:

阿贝云 https://www.abeiyun.com 的免费资源虽然配置不算高,但对学习阶段来说足够了。不用自己花钱买云服务就能有一台独立IP的Linux环境随便折腾,对学生党确实友好。这台服务器上还跑过几个小型的Web项目练手,5M带宽够用。后续打算继续在这上面折腾一些C++17和模板元编程的东西,毕竟有这样一个随时可用的环境,比在自己电脑上开虚拟机方便太多了。

```cpp
#include <iostream>
#include <limits>
#include <iomanip>

int main() {
std::cout << std::setprecision(20);
std::cout << "max() = " << std::numeric_limits<float>::max() << std::endl;
std::cout << "min() = " << std::numeric_limits<float>::min() << std::endl;
std::cout << "lowest() = " << std::numeric_limits<float>::lowest() << std::endl;
std::cout << "epsilon() = " << std::numeric_limits<float>::epsilon() << std::endl;
std::cout << "digits10 = " << std::numeric_limits<float>::digits10 << std::endl;
std::cout << "max_exponent10 = " << std::numeric_limits<float>::max_exponent10 << std::endl;
std::cout << "min_exponent10 = " << std::numeric_limits<float>::min_exponent10 << std::endl;
std::cout << "has_infinity = " << std::numeric_limits<float>::has_infinity << std::endl;
std::cout << "infinity() = " << std::numeric_limits<float>::infinity() << std::endl;
return 0;
}
```

在阿贝云的免费云服务器上用g++编译时加了`-std=c++11`,跑出来的结果让我有点意外:

```
max() = 3.4028234663852885981e+38
min() = 1.175494350822287508e-38
lowest() = -3.4028234663852885981e+38
epsilon() = 1.1920928955078125e-07
digits10 = 6
max_exponent10 = 38
min_exponent10 = -37
has_infinity = 1
infinity() = inf
```

输出`max_exponent10=38`意味着`10^38`数量级是float能表示的极限,而`min_exponent10=-37`对应最小正规化数的数量级。`digits10=6`表示float大约只有6-7位有效十进制精度——这个数字后来坑了我整整两个小时。

事情是这样的:我在写一个迭代累加的算法,要计算一组浮点数的均值。代码大致是这样:

```cpp
float sum = 0.0f;
for (int i = 0; i < 100000; ++i) {
sum += 0.001f;
}
float avg = sum / 100000.0f;
std::cout << "Expected: 1.0, Got: " << avg << std::endl;
```

在阿贝云的免费云服务器上编译运行,输出居然是:

```
Expected: 1.0, Got: 0.9999904632568359375
```

差了将近1e-5。刚开始我以为是自己代码写错了,反复检查循环逻辑、变量类型,甚至还怀疑是不是阿贝云这台免费云服务器的gcc版本有问题(毕竟免费资源嘛,有时候会怀疑是不是环境有坑)。折腾了半天,编译时加了`-Wall -Wextra`没有任何警告,又换了`double`试了一下——结果正常了,输出0.999999999999。这才意识到是`float`精度不够。

问题出在`0.001f`这个字面量上。0.001在二进制下是无限循环小数,float只有23位尾数,每次累加都会舍入,误差随着迭代次数线性累积。10万次累加下来误差累计到了将近1e-5。而`digits10=6`意味着float在数值1附近只有约6位有效数字,1e-5的误差恰好落在精度边界之外。

修复方案有两个思路。第一是直接用`double`代替`float`——double有53位尾数,精度高得多,在这个场景下完全够用。第二是如果必须用float,可以用Kahan求和算法来补偿累积误差:

```cpp
float kahan_sum(float* data, int n) {
float sum = 0.0f;
float compensation = 0.0f;
for (int i = 0; i < n; ++i) {
float y = data[i] - compensation;
float t = sum + y;
compensation = (t - sum) - y;
sum = t;
}
return sum;
}
```

这个算法用一个补偿变量记录每次舍入丢失的低位,下次加法时补回去。改完之后输出恢复正常。

这件事让我对`std::numeric_limits<float>`的几个成员有了更深的理解。`epsilon()`返回的是1.19e-7,表示1和大于1的最小可表示float之间的差值。`digits10=6`意味着把任意float转成十进制再转回来,6位以内是可靠的。这些信息光看文档是记不住的,只有在真实环境中踩过坑才能刻进脑子里。

整个过程都在阿贝云的免费云服务器上完成。SSH连接很顺畅,延迟在30ms左右。编译速度比我想象中快,虽然只有1核1G的配置,但SSD硬盘的IO确实给力。中途还试着重装了一次系统(从CentOS切到Ubuntu),控制面板上一键重装也就几分钟的事。对于这种学习性质的C++开发,完全够用了。免费虚拟主机和免费云服务器这两种产品,我觉得云服务器更适合做这种需要自己编译调试的开发工作,自由度更高。

以后写涉及浮点数比较的代码,应该会先查一下`std::numeric_limits<T>::epsilon()`再决定误差容忍范围,而不是拍脑袋写个`if (abs(a-b) < 1e-6)`。毕竟不同精度类型、不同数值量级下的合理误差阈值完全不同。

阿贝云 https://www.abeiyun.com 的免费资源虽然配置不算高,但对学习阶段来说足够了。不用自己花钱买云服务就能有一台独立IP的Linux环境随便折腾,对学生党确实友好。这台服务器上还跑过几个小型的Web项目练手,5M带宽够用。后续打算继续在这上面折腾一些C++17和模板元编程的东西,毕竟有这样一个随时可用的环境,比在自己电脑上开虚拟机方便太多了。

本文包含AI生成内容

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/1 23:35:38

Kali Linux 中 Nessus 漏洞扫描器的安装、激活与基础扫描实战

1. 先搞清楚 Nessus 在 Kali 里到底扮演什么角色如果你在 Kali Linux 里折腾安全工具&#xff0c;Nessus 这个名字肯定绕不过去。它不是那种命令行下敲几个参数就出结果的小工具&#xff0c;而是一个功能全面、插件库庞大的商业级漏洞扫描器。简单说&#xff0c;它能把你的目标…

作者头像 李华
网站建设 2026/9/1 23:32:51

DeepSeek Harness:AI智能体编排框架的完整实践指南

这次我们来看一个在 AI 编程领域备受关注的项目&#xff1a;DeepSeek Harness。它不是一个新的 AI 模型&#xff0c;而是一个旨在管理和编排多个 AI 模型、工具与服务的智能体框架。简单来说&#xff0c;它让你能像搭积木一样&#xff0c;将不同的 AI 能力&#xff08;如代码生…

作者头像 李华
网站建设 2026/9/1 23:29:53

HarmonyOS 应用开发之应用备份恢复与数据安全详解

应用备份恢复与数据安全一、引言 用户换机、重装系统后&#xff0c;最痛的不是重新下载应用&#xff0c;而是"看过一半的收藏和设置全没了"。HarmonyOS 为应用提供了系统级备份恢复能力&#xff1a;通过声明 BackupExtensionAbility 与 backup_config.json&#xff0…

作者头像 李华
网站建设 2026/9/1 23:28:25

驱动模型匹配:从 driver_register 到bus->match/probe 的绑定路径

设备在 /sys 里看得见却不 probe、compatible 对了仍不绑驱动&#xff1a;根因常在 bus/device/driver 三件套的匹配与绑定&#xff0c;而不是 probe 函数体本身。本文沿 driver_register → bus_add_driver → driver_attach → bus->match → probe 走通一次绑定&#xff…

作者头像 李华
网站建设 2026/9/1 23:26:03

x64dbg脚本编程中文优化:提升逆向分析效率的实践指南

在逆向工程和漏洞分析领域&#xff0c;x64dbg 是一款功能强大的开源调试器&#xff0c;深受安全研究人员的喜爱。然而&#xff0c;其内置的脚本引擎虽然灵活&#xff0c;但使用门槛较高&#xff0c;尤其是对于习惯中文环境的开发者而言&#xff0c;英文的脚本命令和文档常常成为…

作者头像 李华
网站建设 2026/9/1 23:24:00

MKVToolNix跨平台安装与无损混流实战:从GUI到CLI批量处理

这次我们来看一个在视频处理领域几乎绕不开的工具&#xff1a;MKVToolNix。它不是新出的AI模型&#xff0c;也不是需要大显存的深度学习框架&#xff0c;而是一个功能强大、跨平台、完全免费开源的MKV&#xff08;Matroska&#xff09;多媒体容器处理工具套件。对于经常需要处理…

作者头像 李华