我用浮点数做数学得到了一个令人困惑的结果。我的代码永远不会产生负数,这会在我尝试取平方根时导致 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 个样本重新计算总和可以提供很好的运行时间和足够的准确性。谢谢。