gpt4 book ai didi

java - 在给定开始、结束和步骤的情况下生成 List 值序列的最佳方法?

转载 作者:行者123 更新时间:2023-12-01 08:22:42 25 4
gpt4 key购买 nike

我实际上很惊讶我无法在这里找到答案,尽管也许我只是使用了错误的搜索词或其他东西。我能找到的最接近的是 this ,但他们询问生成 double 的特定范围s 具有特定的步长,并且答案将其视为此类。我需要一些可以生成具有任意开始、结束和步长的数字的东西。

我认为在某个地方的图书馆中必须有一些这样的方法,但如果是这样,我就无法轻松找到它(同样,也许我只是使用了错误的搜索词或其他东西)。所以这是我在过去几分钟里自己做的事情:

import java.lang.Math;
import java.util.List;
import java.util.ArrayList;

public class DoubleSequenceGenerator {


/**
* Generates a List of Double values beginning with `start` and ending with
* the last step from `start` which includes the provided `end` value.
**/
public static List<Double> generateSequence(double start, double end, double step) {
Double numValues = (end-start)/step + 1.0;
List<Double> sequence = new ArrayList<Double>(numValues.intValue());

sequence.add(start);
for (int i=1; i < numValues; i++) {
sequence.add(start + step*i);
}

return sequence;
}

/**
* Generates a List of Double values beginning with `start` and ending with
* the last step from `start` which includes the provided `end` value.
*
* Each number in the sequence is rounded to the precision of the `step`
* value. For instance, if step=0.025, values will round to the nearest
* thousandth value (0.001).
**/
public static List<Double> generateSequenceRounded(double start, double end, double step) {

if (step != Math.floor(step)) {
Double numValues = (end-start)/step + 1.0;
List<Double> sequence = new ArrayList<Double>(numValues.intValue());

double fraction = step - Math.floor(step);
double mult = 10;
while (mult*fraction < 1.0) {
mult *= 10;
}

sequence.add(start);
for (int i=1; i < numValues; i++) {
sequence.add(Math.round(mult*(start + step*i))/mult);
}

return sequence;
}

return generateSequence(start, end, step);
}

}

这些方法运行一个简单的循环乘以 step通过序列索引并添加到​​ start抵消。这减轻了连续递增时可能出现的复合浮点错误(例如在每次迭代时将 step 添加到变量中)。

我添加了 generateSequenceRounded方法适用于小数步长可能导致明显浮点错误的情况。它确实需要更多的算术运算,因此在像我们这样对性能极其敏感的情况下,当不需要舍入时,可以选择使用更简单的方法是很好的。我怀疑在大多数一般用例中,舍入开销可以忽略不计。

请注意,我故意排除了处理“异常”参数的逻辑,例如 Infinity , NaN , start > end ,或负值 step大小以简化并希望专注于手头的问题。

下面是一些示例用法和相应的输出:
System.out.println(DoubleSequenceGenerator.generateSequence(0.0, 2.0, 0.2))
System.out.println(DoubleSequenceGenerator.generateSequenceRounded(0.0, 2.0, 0.2));
System.out.println(DoubleSequenceGenerator.generateSequence(0.0, 102.0, 10.2));
System.out.println(DoubleSequenceGenerator.generateSequenceRounded(0.0, 102.0, 10.2));
[0.0, 0.2, 0.4, 0.6000000000000001, 0.8, 1.0, 1.2000000000000002, 1.4000000000000001, 1.6, 1.8, 2.0]
[0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0]
[0.0, 10.2, 20.4, 30.599999999999998, 40.8, 51.0, 61.199999999999996, 71.39999999999999, 81.6, 91.8, 102.0]
[0.0, 10.2, 20.4, 30.6, 40.8, 51.0, 61.2, 71.4, 81.6, 91.8, 102.0]

是否有提供这种功能的现有库?

如果没有,我的方法有什么问题吗?

有没有人对此有更好的方法?

最佳答案

使用 Java 11 Stream API 可以轻松生成序列。

直接的方法是使用 DoubleStream :

public static List<Double> generateSequenceDoubleStream(double start, double end, double step) {
return DoubleStream.iterate(start, d -> d <= end, d -> d + step)
.boxed()
.collect(toList());
}

在具有大量迭代的范围上, double精度误差可能会累积,从而在接近范围末端时产生更大的误差。
可以通过切换到 IntStream 来最小化错误并使用整数和单双乘法器:
public static List<Double> generateSequenceIntStream(int start, int end, int step, double multiplier) {
return IntStream.iterate(start, i -> i <= end, i -> i + step)
.mapToDouble(i -> i * multiplier)
.boxed()
.collect(toList());
}

摆脱一个 double完全没有精度误差, BigDecimal可以使用:
public static List<Double> generateSequenceBigDecimal(BigDecimal start, BigDecimal end, BigDecimal step) {
return Stream.iterate(start, d -> d.compareTo(end) <= 0, d -> d.add(step))
.mapToDouble(BigDecimal::doubleValue)
.boxed()
.collect(toList());
}

例子:
public static void main(String[] args) {
System.out.println(generateSequenceDoubleStream(0.0, 2.0, 0.2));
//[0.0, 0.2, 0.4, 0.6000000000000001, 0.8, 1.0, 1.2, 1.4, 1.5999999999999999, 1.7999999999999998, 1.9999999999999998]

System.out.println(generateSequenceIntStream(0, 20, 2, 0.1));
//[0.0, 0.2, 0.4, 0.6000000000000001, 0.8, 1.0, 1.2000000000000002, 1.4000000000000001, 1.6, 1.8, 2.0]

System.out.println(generateSequenceBigDecimal(new BigDecimal("0"), new BigDecimal("2"), new BigDecimal("0.2")));
//[0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0]
}

方法 iterate在 Java 9 中添加了此签名(3 个参数)。因此,对于 Java 8,代码看起来像
DoubleStream.iterate(start, d -> d + step)
.limit((int) (1 + (end - start) / step))

关于java - 在给定开始、结束和步骤的情况下生成 List<Double> 值序列的最佳方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59440436/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com