Created
April 1, 2013 07:34
-
-
Save komiya-atsushi/5283676 to your computer and use it in GitHub Desktop.
情報落ちを回避する加算処理はこんなものかな?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* なるべく精度を保ちつつ加算する機能を提供します。 | |
* <p> | |
* 情報落ちを回避する仕組みを備えています。 | |
* </p> | |
* | |
* @author KOMIYA Atsushi | |
*/ | |
public class AccurateAdder { | |
/** sum より大きな値を一時的に蓄積するバッファのサイズです */ | |
private final int bufferSize; | |
/** 加算された値を保持します */ | |
private double sum; | |
/** sum に加算するには小さ過ぎる値(誤差)を保持します */ | |
private double error; | |
/** sum より大きな値を格納するバッファです */ | |
private double[] buffer; | |
/** バッファに格納されている値の個数を表します */ | |
private int bufferedCount; | |
/** 計算途中で利用するワークメモリ的な変数です */ | |
private double temp; | |
public AccurateAdder() { | |
this(10); | |
} | |
public AccurateAdder(int bufSize) { | |
this.bufferSize = bufSize; | |
this.buffer = new double[bufSize]; | |
} | |
/** | |
* 加算結果を返却します。 | |
* | |
* @return | |
*/ | |
public double sum() { | |
flushBuffer(); | |
return sum; | |
} | |
/** | |
* 加算結果に加算することのできない累積誤差を返却します。 | |
* | |
* @return | |
*/ | |
public double error() { | |
flushBuffer(); | |
return error; | |
} | |
/** | |
* 情報落ちを極力回避しながら加算します。 | |
* <p> | |
* value が現状の sum よりも大きな値の場合は、sum に加算するのを遅延させます。 value が sum よりも小さければ、現状の | |
* error と value を先に足し合わせ、その結果を sum に加えます。 | |
* </p> | |
* | |
* @param value | |
*/ | |
public void add(double value) { | |
if (value < sum) { | |
temp = (value + error) + sum; | |
error = (value + error) - (temp - sum); | |
sum = temp; | |
} else { | |
buffer[bufferedCount++] = value; | |
if (bufferedCount == bufferSize) { | |
flushBuffer(); | |
} | |
} | |
} | |
/** | |
* バッファに蓄積されている値を sum に足し込みます。 | |
*/ | |
private void flushBuffer() { | |
if (bufferedCount == 0) { | |
return; | |
} | |
Arrays.sort(buffer); | |
for (int i = 0; i < bufferSize; i++) { | |
double v = buffer[i]; | |
if (v < sum) { | |
temp = (v + error) + sum; | |
error = (v + error) - (temp - sum); | |
} else { | |
temp = v + (error + sum); | |
error = (error + sum) - (temp - v); | |
} | |
sum = temp; | |
} | |
bufferedCount = 0; | |
Arrays.fill(buffer, 0); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment