In realtà sono molto sorpreso di non essere riuscito a trovare la risposta qui, anche se forse sto solo usando termini di ricerca sbagliati o qualcosa del genere. Il più vicino che ho trovato è questo , ma mi chiedono di generare un intervallo specifico di double
s con una specifica dimensione del passo e le risposte lo trattano come tale. Ho bisogno di qualcosa che generi i numeri con inizio, fine e dimensione del passo arbitrari.
Immagino che ci debba essere un metodo come questo in una libreria già da qualche parte, ma in tal caso non sono stato in grado di trovarlo facilmente (di nuovo, forse sto solo usando i termini di ricerca sbagliati o qualcosa del genere). Quindi, ecco cosa ho preparato da solo negli ultimi minuti per fare questo:
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);
}
}
Questi metodi eseguono un semplice ciclo moltiplicando step
per l'indice di sequenza e aggiungendolo start
all'offset. Ciò mitiga gli errori di virgola mobile che si verificano con un'incremento continuo (come l'aggiunta step
di una variabile ad ogni iterazione).
Ho aggiunto il generateSequenceRounded
metodo per quei casi in cui una dimensione del gradino frazionaria può causare notevoli errori in virgola mobile. Richiede un po 'più di aritmetica, quindi in situazioni estremamente sensibili alle prestazioni come la nostra, è bello avere la possibilità di utilizzare il metodo più semplice quando l'arrotondamento non è necessario. Ho il sospetto che nella maggior parte dei casi di utilizzo generale l'arrotondamento sarebbe trascurabile.
Si noti che ho volutamente escluso la logica per la gestione di argomenti "anomale", come Infinity
, NaN
, start
> end
, o un negativo step
dimensione per la semplicità e il desiderio di concentrarsi sulla questione a portata di mano.
Ecco alcuni esempi di utilizzo e output corrispondente:
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]
Esiste una libreria esistente che fornisce già questo tipo di funzionalità?
In caso contrario, ci sono problemi con il mio approccio?
Qualcuno ha un approccio migliore a questo?