De hecho, estoy muy sorprendido de que no haya podido encontrar la respuesta a esto aquí, aunque tal vez solo estoy usando los términos de búsqueda incorrectos o algo así. Lo más cercano que pude encontrar es esto , pero preguntan sobre la generación de un rango específico de double
s con un tamaño de paso específico, y las respuestas lo tratan como tal. Necesito algo que genere los números con inicio arbitrario, final y tamaño de paso.
Calculo que hay tiene que haber algún método como este en una biblioteca en algún lugar ya, pero si es así yo no era capaz de encontrar fácilmente (de nuevo, tal vez sólo estoy usando los términos de búsqueda mal o algo). Así que esto es lo que he cocinado solo en los últimos minutos para hacer esto:
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);
}
}
Estos métodos ejecutan un bucle simple multiplicando el step
por el índice de secuencia y agregando al start
desplazamiento. Esto mitiga los errores de coma flotante compuestos que ocurrirían con un incremento continuo (como agregar el step
a una variable en cada iteración).
Agregué el generateSequenceRounded
método para aquellos casos en que un tamaño de paso fraccional puede causar errores notables de punto flotante. Requiere un poco más de aritmética, por lo que en situaciones extremadamente sensibles al rendimiento como la nuestra, es bueno tener la opción de usar el método más simple cuando el redondeo es innecesario. Sospecho que en la mayoría de los casos de uso general, la sobrecarga de redondeo sería insignificante.
Tenga en cuenta que Excluí intencionadamente lógica para el manejo de argumentos "anormales", tales como Infinity
, NaN
, start
> end
, o un negativo step
tamaño de la simplicidad y el deseo de centrarse en la cuestión que nos ocupa.
Aquí hay un ejemplo de uso y salida correspondiente:
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 ya una biblioteca que brinde este tipo de funcionalidad?
Si no, ¿hay algún problema con mi enfoque?
¿Alguien tiene un mejor enfoque para esto?