我需要在Derby中创建一个用户自定义聚合(UDA)函数(具体来说,是一个Variance
函数),但我仍然坚持使用正确的编写方法。
到目前为止,我有UDA的“模板”:
public class Variance<V extends Comparable<V>> implements Aggregator<V,V,Variance<V>> {
private ArrayList<V> _values;
public Variance() {/*Empty constructor*/}
public void init() {_values = new ArrayList<V>(); }
public void accumulate(V v) { _values.add(v); }
public void merge(Variance<V> o) { _values.addAll(o._values); }
public V terminate() {
// Here is my issue!!!
}
}
我面临的问题是:要计算方差,我需要计算这样的事情:
V sum, sumSq;
int n = _values.size();
if(n <= 0)
return null;
// Initialize sum and sumSq to "zero"
for(V v : _values) {
sum += v; // Or somehow add v to sum
sumSq += Math.pow(v, 2); // Or somehow add (v^2) to sumSq
}
return (sumSq - n * Math.pow(sum / n, 2)) / n;
...但我不知道如何判断这只对数字类型(整数,十进制或浮点值)有效。
我想我的代码中遗漏了一些内容,但我不知道是否有办法告诉该程序V
是数字的,因此,我可以对类型{的值使用算术运算{1}}。
所以,具体问题是:
V
的定义(稍微扩展一个“数字”类,如V
)?答案 0 :(得分:1)
查看Derby的数据类型:
DECIMAL = java.math.BigDecimal
INTEGER = java.lang.Integer
FLOAT = java.lang.Float or java.lang.Double
FLOAT将根据您在创建时指定的精度转换为不同的Java对象,默认为java.lang.Double
添加数字
你遇到的第一个问题就是简单地将值相加(很多二元运算符的错误操作数类型&#39; +&#39; 错误)。即使你可以使用Integer,Float和Double工作,你会发现因为BigDecimal没有直接映射到Java原语,所以它不能与标准的原始算术运算符一起使用,因此它具有自己的add方法在对象上。
引用,Mark Peters answer to a similar issue;
有些方法你可以一起破解这个,但老实说, 仿制药根本就不是去这里的方法。为每个人构建一个方法 具体的原始包装类型并分别实现它们。它&#39; 11 让它变得通用是太令人头疼的事了;算术 操作不可能一般发生。
平方值
您遇到的第二个问题是您正在使用电源方法。
Math.pow()使用双参数 - 因此Integer或Double计算应该没问题。 Float可能会显示意外的结果,因为将float转换为double会导致转换后的值出现奇怪的额外数字。
Math.pow的结果类型是Double,您可以通过定义聚合器来解决这个问题,以便终止方法结果类型始终为Double,例如:
public class Variance<V extends Number & Comparable<V>>
implements Aggregator<V, Double, Variance<V>> {
正如我们之前看到的,BigDecimal与其他人有点不同,并且有自己的pow()方法,其结果类型是BigDecimal值。
<强>结论强>
鉴于上述情况,我建议不要尝试通用解决方案,而是为要支持的每个类类型实现多个方差聚合器。例如你可以实现类似的东西:
Aggregator<Integer, Double, Variance<Integer>>
Aggregator<Double, Double, Variance<Double>>
Aggregator<Float, Double, Variance<Float>>
Aggregator<BigDecimal, BigDecimal, Variance<BigDecimal>>
答案 1 :(得分:0)
//that is not the best answer, but works
import org.apache.derby.agg.Aggregator;
import java.util.ArrayList;
public class Variance<V extends Double> implements Aggregator<V,V,Variance<V>> {
private ArrayList<V> list =null;
public Variance() {}
public void init() {
list= new ArrayList<>();
}
public void accumulate(V value) {
list.add(value);
}
public void merge(Variance<V> another) {
list.addAll(another.list);
}
public V terminate() {
double sum=0, sumSq=0;
int n = list.size();
if(n <= 0)
return null;
// Initialize sum and sumSq to "zero"
for(Double v : list) {
sum += v; // Or somehow add v to sum
sumSq += Math.pow(v, 2); // Or somehow add (v^2) to sumSq
}
return (V)(new Double((sumSq - n * Math.pow(sum / n, 2)) / n) ) ;
}
public static void main(String [] args) {
Variance<Double> v= new Variance<>();
v.init();
v.accumulate(new Double(8.0));
v.accumulate(new Double(6.0));
v.accumulate(new Double(10.0));
System.out.println(v.terminate());
}
}