我得到了一个令人困惑的结果与浮游物做数学。我有代码,不应该产生负数,产生负数,当我尝试取平方根时会导致NaN。RMS的快速计算给出Java中的NaN - 浮点错误?
此代码在测试中似乎工作得很好。然而,当在真实世界(即可能非常小的,七个和八个负指数)数字上进行操作时,最终总和变为负数,导致NaN。理论上,减法步骤只删除已添加到sum
的数字;这是一个浮点错误问题?有什么方法可以解决它吗?
的代码:
public static float[] getRmsFast(float[] data, int halfWindow) {
int n = data.length;
float[] result = new float[n];
float sum = 0.000000000f;
for (int i=0; i<2*halfWindow; i++) {
float d = data[i];
sum += d * d;
}
result[halfWindow] = calcRms(halfWindow, sum);
for (int i=halfWindow+1; i<n-halfWindow; i++) {
float oldValue = data[i-halfWindow-1];
float newValue = data[i+halfWindow-1];
sum -= (oldValue*oldValue);
sum += (newValue*newValue);
float rms = calcRms(halfWindow, sum);
result[i] = rms;
}
return result;
}
private static float calcRms(int halfWindow, float sum) {
return (float) Math.sqrt(sum/(2*halfWindow));
}
对于一些背景: 我试图优化计算的轧制根意味着对信号数据方(RMS)功能的功能。优化非常重要;这是我们加工过程中的热点。基本方程很简单 - http://en.wikipedia.org/wiki/Root_mean_square - 在窗口上求和数据的平方,除以窗口大小,然后取平方。
原始代码:
public static float[] getRms(float[] data, int halfWindow) {
int n = data.length;
float[] result = new float[n];
for (int i=halfWindow; i < n - halfWindow; i++) {
float sum = 0;
for (int j = -halfWindow; j < halfWindow; j++) {
sum += (data[i + j] * data[i + j]);
}
result[i] = calcRms(halfWindow, sum);
}
return result;
}
此代码是缓慢的,因为它读取,而不是在窗口取重叠优点从在每个步骤在阵列整个窗口。预期的优化是使用该重叠,通过移除最旧的值并添加最新的值。
我已经仔细检查了新版本中的数组索引。它似乎按预期工作,但我肯定在这方面可能是错的!
更新: 随着我们的数据,这已经足够的sum
类型更改为双。不知道为什么没有发生在我身上。但是我留下了负面支票。而且FWIW,我还能够实施一个sol'n,每400个样本重新计算总和就可以提供很好的运行时间和足够的准确性。谢谢。
试着用'double'而不是'float'。但是可能需要检查负值。 – 2013-03-14 16:27:13
你的数据的范围是什么,halfWindow的最大值是多少?你的float数据有24位有效数字。他们的确切正方形有48位或更少。如果你将'float'缩放为整数并将其转换为'long',那么你有15位空余空间,所以如果该范围的跨度不是太长,那么可以用'long'中的精确算术来保持和。伟大和halfWindow不是太大。这只有在** all **你的数据接近你提到的1e-7和1e-8时才可行。更大的数据会使范围过大。 “双头”的“头部和尾部”方法可能会有效。 – 2013-03-14 17:26:09