Java - 函数式浮点计算
Java - floating point calc in functional style
我猜这里 sm
和 sm2
由于浮点限制不相等:
double sm = -1.22 + (0.6027852837247973 + 0.8920332205475238);
double sm2 = -1.22 + 0.6027852837247973 + 0.8920332205475238;
System.out.println("sm = "+sm);
System.out.println("sm2 = "+sm2);
System.out.println("sm-sm2 = "+(sm-sm2));
结果是:
sm = 0.27481850427232124
sm2 = 0.27481850427232113
sm-sm2 = 1.1102230246251565E-16
我猜它不是零,因为运算顺序?
无论如何,在这种情况下我想问的是 - 如何拥有这段代码的等价物:
double r2 = 0;
for(double o : ar){
r2+=o*2;
}
r2 -= k;
函数式风格(例如像这样,但由于这是第一次操作,我的输出有问题):
Arrays.stream(ar)
.map(o -> o*2)
.reduce(-k, Double::sum);
正如您在问题中提到的,操作顺序很重要。当您使用流时,无法保证执行顺序。除此之外,您使用流的方法还有另一个问题,那就是 identity
参数的值 - k
在您的情况下(我假设您想从结果中减去一些非零值) . reduce(double identity, DoubleBinaryOperator accumulator)
中的标识和累加器函数的值必须使以下语句始终为真:
accumulator.apply(identity, x) = x // for any value of x
累加器 Double::sum
(与 (d1, d2) -> Double.sum(d1, d2)
相同)有效标识的唯一值为 0。
JavaDoc 参考:
double java.util.stream.DoubleStream.reduce(double identity, DoubleBinaryOperator op)
Performs a reduction on the elements of this stream, using the provided identity value and an associative accumulation function, and returns the reduced value. This is equivalent to:
double result = identity;
for (double element : this stream)
result = accumulator.applyAsDouble(result, element)
return result;
but is not constrained to execute sequentially.
The identity value must be an identity for the accumulator function. This means that for all x, accumulator.apply(identity, x) is equal to x. The accumulator function must be an associative function.
This is a terminal operation.
你可以尝试这样的事情(正如@VLAZ 建议的那样):
double calculate(double[] values, double k) {
return DoubleStream.of(values).map(d -> d * 2).reduce(0, Double::sum) - k;
}
更新
正如@LouisWasserman 所建议的,可以通过将 reduce(0, Double::sum)
替换为 sum()
:
来简化 calculate
方法
double calculate(double[] values, double k) {
return DoubleStream.of(values).map(d -> d * 2).sum() - k;
}
我猜这里 sm
和 sm2
由于浮点限制不相等:
double sm = -1.22 + (0.6027852837247973 + 0.8920332205475238);
double sm2 = -1.22 + 0.6027852837247973 + 0.8920332205475238;
System.out.println("sm = "+sm);
System.out.println("sm2 = "+sm2);
System.out.println("sm-sm2 = "+(sm-sm2));
结果是:
sm = 0.27481850427232124
sm2 = 0.27481850427232113
sm-sm2 = 1.1102230246251565E-16
我猜它不是零,因为运算顺序?
无论如何,在这种情况下我想问的是 - 如何拥有这段代码的等价物:
double r2 = 0;
for(double o : ar){
r2+=o*2;
}
r2 -= k;
函数式风格(例如像这样,但由于这是第一次操作,我的输出有问题):
Arrays.stream(ar)
.map(o -> o*2)
.reduce(-k, Double::sum);
正如您在问题中提到的,操作顺序很重要。当您使用流时,无法保证执行顺序。除此之外,您使用流的方法还有另一个问题,那就是 identity
参数的值 - k
在您的情况下(我假设您想从结果中减去一些非零值) . reduce(double identity, DoubleBinaryOperator accumulator)
中的标识和累加器函数的值必须使以下语句始终为真:
accumulator.apply(identity, x) = x // for any value of x
累加器 Double::sum
(与 (d1, d2) -> Double.sum(d1, d2)
相同)有效标识的唯一值为 0。
JavaDoc 参考:
double java.util.stream.DoubleStream.reduce(double identity, DoubleBinaryOperator op)
Performs a reduction on the elements of this stream, using the provided identity value and an associative accumulation function, and returns the reduced value. This is equivalent to:
double result = identity; for (double element : this stream) result = accumulator.applyAsDouble(result, element) return result;
but is not constrained to execute sequentially. The identity value must be an identity for the accumulator function. This means that for all x, accumulator.apply(identity, x) is equal to x. The accumulator function must be an associative function.
This is a terminal operation.
你可以尝试这样的事情(正如@VLAZ 建议的那样):
double calculate(double[] values, double k) {
return DoubleStream.of(values).map(d -> d * 2).reduce(0, Double::sum) - k;
}
更新
正如@LouisWasserman 所建议的,可以通过将 reduce(0, Double::sum)
替换为 sum()
:
calculate
方法
double calculate(double[] values, double k) {
return DoubleStream.of(values).map(d -> d * 2).sum() - k;
}