C++频率直方图统计代码问题:最大值等于区间上限时计数错误
直方图统计中最大值匹配区间上限的计数错误修复方案
问题分析
你的代码在统计直方图频率时,当数组最大值恰好等于最后一个区间上限时,会出现统计项数量超出划分区间数、最后一个区间计数错误的问题。例如划分10个区间时,实际得到11个统计项,最后一个区间的正确计数应为4,却被拆分为3和1。
根源在于两点:
- 浮点数精度误差:
class_w是浮点数,多次累加range_top后,实际值会略小于理论上限(比如3.1变成3.099999...),导致最大值被错误判定为超出区间,触发额外的区间推进逻辑。 - 循环逻辑缺陷:依赖
range_top累加的方式易受精度影响,且处理完所有元素后无条件执行hist.push_back(freq),导致统计项数量失控。
解决方案
推荐使用区间索引直接计算的方式,彻底避免浮点数累加的精度问题,同时确保统计项数量与划分区间数一致。
修改后的代码
#include <iostream> #include <vector> #include <algorithm> using namespace std; vector<float> lengths = { 2.1, 2.5, 1.8, 2.2, 2.9, 2.0, 1.5, 2.8, 2.3, 2.6, 3.1, 2.9, 2.7, 1.8, 2.2, 2.4, 1.9, 2.3, 2.0, 2.5}; vector<int> hist; int divisions; int main(void) { sort(lengths.begin(), lengths.end()); cin >> divisions; float max_val = lengths.back(); float class_w = max_val / divisions; // 初始化直方图为指定划分数量的0值,确保统计项数量正确 hist.assign(divisions, 0); for (float x : lengths) { // 计算当前元素所属的区间索引 int idx = static_cast<int>(x / class_w); // 处理最大值刚好等于区间上限的情况,避免索引越界 if (idx == divisions) { idx = divisions - 1; } hist[idx]++; } // 输出区间上限序列 for (int i = 1; i <= divisions; ++i) { cout << class_w * i << " "; } cout << endl; // 输出直方图统计结果 for (int count : hist) { cout << count << " "; } cout << endl; // 输出排序后的数组 for (float y : lengths) { cout << y << " "; } cout << endl; return 0; }
关键改进点
- 固定统计项数量:通过
hist.assign(divisions, 0)初始化直方图,确保统计项数量与划分区间数完全一致,不会出现额外项。 - 直接计算区间索引:用
x / class_w计算元素所属区间,避免浮点数累加带来的精度误差;对最大值单独处理,防止索引越界。 - 逻辑简洁可靠:移除复杂的while循环推进逻辑,代码可读性和稳定性大幅提升。
验证结果
当划分为10时,运行修改后的代码会得到正确的直方图统计结果:0 0 0 0 1 2 4 5 4 4,与预期完全一致。
内容的提问来源于stack exchange,提问作者VALKYRIEiSr
相关产品推荐
相关产品推荐

