我得到了一個令人困惑的結果與浮游物做數學。我有代碼,不應該產生負數,產生負數,當我嘗試取平方根時會導致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