更准确的平均方法是ARR[0]/N+ARR[1]/N+ARR[N-1]/N或(ARR[0]+ARR[1]..+ARR[N
What is more accurate way to average, ARR[0]/N+ARR[1]/N...+ARR[N-1]/N or (ARR[0]+ARR[1]...+ARR[N-1])/N in double?
计算一组数字ARR[0]/N+ARR[1]/N...+ARR[N-1]/N
或(ARR[0]+ARR[1]...+ARR[N-1])/N
的平均值的更准确方法是什么?(ARR
是一组数字,N
是该组数字的计数)
假设我有一组数字,每个数字的范围从0.0
到1.0
(它们是双\浮点数),有数千个甚至数百万个。
我对递归平均等新方法持开放态度(将双细胞平均到数组中,然后再次平均,直到输出一个细胞数组)。
如果接近零的值非常接近零,则在求和时会出现舍入问题(可能是向上或向下舍入错误),或者在对大量数字求和时,会出现任何数字范围的舍入问题。解决这个问题的一种方法是使用一个求和函数,该函数只将具有相同指数的数字相加(直到您调用getsum()来获得总和,它会使指数尽可能接近)。示例C++类(注意,代码是使用Visual Studio编译的,在uint64_t可用之前编写)。
// SUM contains an array of 2048 IEEE 754 doubles, indexed by exponent,
// used to minimize rounding / truncation issues when doing
// a large number of summations
class SUM{
double asum[2048];
public:
SUM(){for(int i = 0; i < 2048; i++)asum[i] = 0.;}
void clear(){for(int i = 0; i < 2048; i++)asum[i] = 0.;}
// getsum returns the current sum of the array
double getsum(){double d = 0.; for(int i = 0; i < 2048; i++)d += asum[i];
return(d);}
void addnum(double);
};
void SUM::addnum(double d) // add a number into the array
{
size_t i;
while(1){
// i = exponent of d
i = ((size_t)((*(unsigned long long *)&d)>>52))&0x7ff;
if(i == 0x7ff){ // max exponent, could be overflow
asum[i] += d;
return;
}
if(asum[i] == 0.){ // if empty slot store d
asum[i] = d;
return;
}
d += asum[i]; // else add slot to d, clear slot
asum[i] = 0.; // and continue until empty slot
}
}
使用sum类的示例程序:
#include <iostream>
#include <iomanip>
using namespace std;
static SUM sum;
int main()
{
double dsum = 0.;
double d = 1./5.;
unsigned long i;
for(i = 0; i < 0xffffffffUL; i++){
sum.addnum(d);
dsum += d;
}
cout << "dsum = " << setprecision(16) << dsum << endl;
cout << "sum.getsum() = " << setprecision(16) << sum.getsum() << endl;
cout << "0xffffffff * 1/5 = " << setprecision(16) << d * (double)0xffffffffUL << endl;
return(0);
}
(ARR[0]+ARR[1]...+ARR[N-1])/N
更快、更准确,因为使用N
可以省略无用的除法,这会减慢计算过程并增加计算错误。
如果你有一堆浮点数,获得平均值的最准确方法如下:
template<class T> T mean(T* arr, size_t N) {
std::sort(+arr, arr+N, [](T a, T b){return std::abs(a) < std::abs(b);});
T r = 0;
for(size_t n = 0; n < N; n++)
r += arr[n];
return r / N;
}
要点:
- 数量级最小的数字首先相加以保留有效数字
- 只有一个除法,以减少舍入误差
不过,中间金额可能会变得太大。
相关文章:
- arr[-1]在c++中的奇怪行为
- 向量 <int> a {N, 0} 和 int arr a[N] = {0} 的时间复杂度有什么区别
- 在C++中用新表达式制作 arr[n][n]
- different between int **arr =new int [ n]; and int a[i][j]?
- arr[n] 是否以 C++ 为单位打印数组的长度?
- 为什么存储在数组中的地址值与其自己的地址相同,它应该指向某个不同的地址(&arr[0])?
- C++:' arr '和' arr[] '有什么区别
- 在 C/C++ 中将数组作为形式参数作为 int arr[] 和 int arr[N] 传递的区别
- 为什么 arr[i++] 与 arr[i]++ 会这样做?
- 这段代码中的arr[s[i]-'a']有什么用,为什么我们用"a"减去所有字符?
- 澄清了 strcpy() 在像这样初始化字符数组时的工作 *Arr.
- 如何理解"vector<int> avector (arr, arr + sizeof(arr) / sizeof(arr[0]) )"?
- 声明数组>> int arr[] 时出错;在C++(虽然在 Java 中有效)?
- 矢量<bool> arr 重置问题
- 根在 arr[0] 的二进制堆有什么好处
- arr[i] = i++ 和 i = i + 1 语句在 C 和 C++ 中的行为
- 访问函数中 const char *arr[] 的元素
- 数组问题:变量周围的堆栈'arr'已损坏
- 失败,dummy_array<int, 6> arr();
- C 将1D动态数组施放到2D数组以使用常规索引(例如ARR [i] [J])