我正在制作一个音乐生成程序,需要从0.125、0.25和0.5中选择一组x个随机数,使它们的和为1。我无法想出一种既能保留随机元素又能整洁地完成此操作的方法。
谢谢!
谢谢!
只需列举所有可能总和为1的组合(并不是很多),并将它们存储在数组中。 然后只需为该数组计算一个随机索引号以获取随机组合。
有9种组合可以加起来得到1。如果您完全不关心顺序,那么只需在1和9之间随机选择一个数字即可。
如果您关心顺序,则需要排列。集合{.5,.25,.25}有3!个排列:
然而,您可能只想计算唯一的排列。
对于每个集合,您可以使用像这样的算法来生成唯一的排列。 http://www.kerrywong.com/2006/04/14/generating-unique-permutations-programmatically/
一旦您知道所有排列(或唯一排列),就可以使用随机数选择其中一个排列。
如果您关心以后扩展值,您可能需要考虑更动态的方法。避免硬编码值和逻辑。以下解决方案可能有所帮助。在下面的示例中,最大值1是可配置的,可以用于相加的值集也是可配置的。加载列表(从文件或输入)然后程序就可以运行了。这假设在运行之前已将列表按最低到最高值排序。
public class MusicGeneration{
private List<Double> values = new ArrayList<Double>();
Random rand = new Random();
private double max_value = 0;
public MusicGeneration() {
max_value = 10;
values.add(0.125);
values.add(0.25);
values.add(0.5);
values.add(0.75);
}
private void createMusic() {
double total = 0;
while (total < max_value) {
int i = rand.nextInt(maxChoice(total));
System.out.println("Picked :: " + values.get(i));
total += values.get(i);
System.out.println("Total :: " + total);
}
}
private int maxChoice(double total) {
int size = values.size() - 1;
while (size > 0) {
if ((max_value - total) >= values.get(size)) {
System.out.println("Returning " + (size + 1));
return (size + 1);
}
size--;
}
return 1;
}
public static void main(String args[]) {
MusicGeneration play = new MusicGeneration();
play.createMusic();
}
}
一种迭代解决方案,如果可能性太大,则可以轻松地进行泛化。
只需检查每个步骤可以合法的数字,并根据其生成下一个数字。
Java 代码:
static Random random = new Random();
public static double getRandom(double[] l) {
int i = random.nextInt(l.length);
return l[i];
}
public static List<Double> getRandNums() {
List<Double> l = new LinkedList<Double>();
double x = 1;
double[] arr1 = { 0.125, 0.25, 0.5 };
double[] arr2 = { 0.125, 0.25 };
double[] arr3 = { 0.125 };
double r;
while (x > 0) {
if (x >= 0.5) {
r = getRandom(arr1);
} else if (x >= 0.25) {
r = getRandom(arr2);
} else {
r = getRandom(arr3);
}
l.add(r);
x -= r;
}
return l;
}