【问题标题】:Finding the average of an array of doubles from file input [closed]从文件输入中查找双精度数组的平均值[关闭]
【发布时间】:2013-01-31 00:11:56
【问题描述】:

到目前为止,我试图找到一种方法来获取该数组的平均值的尝试都没有结果。任何帮助将不胜感激。

#include <iostream>
#include <algorithm>
#include <numeric>
#include <vector>
#include <iterator>
#include <string>
#include <iostream>
#include <fstream>
using namespace std;
int main( )
{
    const int MAX = 100;
    double voltages[MAX];
    double average;
    ifstream thefile("c:\\voltages.txt");
        if(!thefile) 
    {
                cout<<"Error opening file"<<endl;
                system("pause");
                exit(1);
    }
        for(int count = 0; count < MAX; count++)
    {
                thefile >> voltages[count];
                cout << voltages[count++] << endl;
                average = voltages[count++]/count;
        if(count == 0 || thefile.eof())
    {
                break;
    }
    }
    cout << average;
    cout << "\n";
    system("PAUSE");
    return 0;
} 

电压文件是

100.8

120.4

121.4

111.9

123.4

但最多可以有 100 个双打。

【问题讨论】:

  • 您在每次循环迭代中增加 count 3 次。你确定那是故意的吗?无论如何,我会选择一个向量来读取文件,然后将std::accumulate 除以大小。
  • 为什么要计算每个循环的平均值。这是浪费效率。使用双精度数作为总数,并在循环外最后除以计数器。
  • 此外,您永远不会对任何地方的电压值求和,这是计算平均值的一个非常重要的步骤。
  • while (thefile.eof()) { thefile >> tmp;总和+=tmp ; cnt++ } return (cnt==0)?0: sum/cnt;

标签: c++ arrays file-io double average


【解决方案1】:

要计算存储在任何 C++ 容器(甚至是原始数组)中的数字的平均值,请使用以下方法。求和除以元素个数:

std::accumulate(std::begin(v), std::end(v), 0.0) / (std::end(v) - std::begin(v));

示例代码:

With std::vector/ With raw array(注意只有vector/array的定义改变了!)

此代码不检查零长度,这会产生除以零。这将返回一个NaN 值。这种情况可以通过if (std::begin(v) == std::end(v))提前发现。如果您不想返回NaN,您可以根据需要处理此类极端情况:

  • 返回一个明确定义的值,例如0.0
  • 抛出异常
  • 打印警告并退出(本质上与异常相同,但不能被捕获)
  • 自定义错误处理,例如将布尔错误变量设置为 true

【讨论】:

  • 代码在长度为 0 的向量上运行。
  • @ShaunMarko 谢谢。这应该作为个别代码中的特殊情况添加。有些人更喜欢定义明确的结果(如 0.0)、一些 NaN 和一些例外。还是打印警告?我不知道人们喜欢什么。我在答案中将其作为警告。
  • @ShaunMarko 好吧,boom 在这里可能是错误的术语。它不会使程序崩溃,但表达式的计算结果为 NaN,它仍然是“有效的”并且只是一个异常值。
  • @leemes:除以零是未定义的行为 - 它可能对您评估为 NaN,但对其他人来说可能会繁荣。也许:(std::end(v) - std::begin(v)) ? std::accumulate(std::begin(v), std::end(v), 0.0) / (std::end(v) - std::begin(v)) : 0.0 还有一个挑剔:该表达式仅适用于具有随机访问迭代器或数组的容器。
  • @MichaelBurr 已经考虑过非随机访问迭代器的问题。有类似 std::size 或类似的东西吗?
【解决方案2】:

最好先有一个带有运行总数的双精度数,然后是一个计数器,然后对平均值进行 TOTAL/COUNT。不需要向量等等。

PS:对于 fstream 使用 .get() 而不是 .eof() 是一个更好的主意,因为有时文本编辑器会在末尾添加一个 '\n' 字符(给你一个空字符串额外的迭代和可能的错误)。

对于数组和类似的东西,在 [ ] 内递增通常也是一个坏主意。最好在括号外使用 [count+1] 和/或递增计数。

【讨论】:

    【解决方案3】:

    对平均值使用递归定义:

    avg_n= ((n-1)* avg_n_1 + val) / n;
    

    val 是第 n 个数据的值。
    avg_n 是当前平均值
    avg_n_1 是前一次迭代的平均值(n-1 个值的平均值)

    最后是循环中的最后一条语句:

    avg_n_1 = avg_n;
    

    这样您就可以计算平均值,而无需事先知道您将读取多少个值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多