一覧<ダブル>値のシーケンス与えられた開始、終了、およびステップを生成するための最良の方法?

NanoWizard:

私は実際には非常に多分私はちょうど間違った検索語か何かを使用していますけれども、私は、ここではこれに対する答えを見つけることができませんでした驚いて。私は見つけることができる最も近いですこれが、彼らは、特定の範囲の生成について尋ねる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分数のステップサイズが目立つ浮動小数点エラーが発生する可能性があり、これらの例のための方法を。それはそうな我々として非常にパフォーマンスの影響を受けやすい状況で、それは丸めが不要な場合に簡単な方法を使用してのオプションを持ってうれしいです、もう少し算術必要です。私は、最も一般的なユースケースで丸めオーバーヘッドが無視できないだろうと思われます。

私は意図的のような「異常」の引数を処理するためのロジックを除外することを注意InfinityNaNstart> 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]

すでにこの種の機能を提供し、既存のライブラリはありますか?

ない場合は、私のアプローチのいずれかの問題がありますか?

誰もがこれまでより良い方法がありますか?

Evgeniy Khyst:

シーケンスは、簡単にJavaの11のストリーム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]
}

方法反復この署名付き(3つのパラメータ)は、Java 8コード外観等については、Java 9そうで添加しました

DoubleStream.iterate(start, d -> d + step)
    .limit((int) (1 + (end - start) / step))

おすすめ

転載: http://10.200.1.11:23101/article/api/json?id=435593&siteId=1