Je suis en fait très surpris de ne pas avoir pu trouver la réponse à cela ici, bien que j'utilise peut-être simplement les mauvais termes de recherche ou quelque chose. Le plus proche que j'ai pu trouver est celui-ci , mais ils demandent de générer une plage spécifique de double
s avec une taille de pas spécifique, et les réponses le traitent comme tel. J'ai besoin de quelque chose qui générera les nombres avec une taille de début, de fin et de pas arbitraire.
Je pense qu'il doit déjà y avoir une méthode comme celle-ci dans une bibliothèque, mais si c'est le cas, je n'ai pas pu la trouver facilement (encore une fois, j'utilise peut-être les mauvais termes de recherche ou quelque chose). Voici donc ce que j'ai préparé par moi-même au cours des dernières minutes pour le faire:
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);
}
}
Ces méthodes exécutent une boucle simple multipliant le step
par l'index de séquence et ajoutant au start
décalage. Cela atténue les erreurs de virgule flottante qui se produiraient avec une incrémentation continue (comme l'ajout de la step
à une variable à chaque itération).
J'ai ajouté la generateSequenceRounded
méthode pour les cas où une taille de pas fractionnaire peut provoquer des erreurs notables en virgule flottante. Cela nécessite un peu plus d'arithmétique, donc dans des situations extrêmement sensibles aux performances comme la nôtre, il est agréable d'avoir la possibilité d'utiliser la méthode plus simple lorsque l'arrondi n'est pas nécessaire. Je soupçonne que dans la plupart des cas d'utilisation générale, les frais généraux d'arrondi seraient négligeables.
Notez que je la logique intentionnellement exclue pour le traitement des arguments « anormaux » tels que Infinity
, NaN
, start
> end
ou négatif step
taille pour la simplicité et le désir de se concentrer sur la question à portée de main.
Voici un exemple d'utilisation et la sortie correspondante:
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]
Existe-t-il une bibliothèque existante qui fournit déjà ce type de fonctionnalité?
Sinon, y a-t-il des problèmes avec mon approche?
Quelqu'un at-il une meilleure approche à ce sujet?