作者zanyking (遥远的旅人)
看板java
标题Re: [问题] 乱数产生一个矩阵
时间Tue Mar 14 23:57:53 2006
※ 引述《AI3767 (AI3767)》之铭言:
: 不好意思, 这个主题已经很久了
: 想说试着写一个一般型的来试看看
: 下面有主要程式的程式码, 写的不好请见谅
: 作法很直观, 就是看机率落在那个范围
: 再从那个范围内取乱数
: 主要由Factory method取得一个物件
: 然後这个物件就可以用getRand()来取值了
: package tw.edu.ccu.cs.ailab;
: import java.util.Arrays;
: import java.util.Random;
: public class RangeRandom {
: private Random genRandom;
: private int[] accumulateArray;
: private int offset;
: private float[] probabilityArray;
: private RangeRandom(int[] rangeArr, int off, float[] probArr) {
: offset = off;
: probabilityArray = probArr;
: setAccumulateArray(rangeArr);
: setProbArray(probArr);
这里的写法很可怕,难懂,又容易错。
两个set方法互相要求对方的成员跟自己的长度要一样,而且你是先让:
probabilityArray = probArr;来方便你取得正确的长度
可是在setProbArray(probArr);却又一定会把probArr指向另外一个值。
这样写很危险。
: genRandom = new Random();
: } //{END constructor}
: /** 利用 <code>range</code> 阵列所设定的各个范围大小, 相对同个索引位置的
: * <code>probs</code> 阵列是该位置范围的机率. <p>
: * 举例当呼叫 <code>createRangeRandom(new int[]{1,3,2}, 2,
: * new float[]{0.2f,0.7f,0.1f})</code>,<br>
: * 则乱数产生 2 的机率有 20%; 3, 4, 或5 的机率有 70%; 6 或 7 的机率有 10%.
这里非常的难懂、也非常的不好用。那个new int[]{1,3,2}
指的是从2开始1个数、3个数、2个数吧?
也就是说如果我想要2,3,4,5,6,7分别有不同的机率我就要宣告:
rangs = new int[]{1,1,1,1,1,1};
probs = new float[]{0.1f,0.1f,0.1f,0.1f,0.2f,0.3f};
这样的使用者介面超难用。
因为事实上,我并不需要知道个别值占总体的比例,我只需要知道一个纯量的权重就好。
也就是说像这样:
new int[]{12,123,34,1,6,77}
至於个别比例是多少,是写程式的人要负责算的。
: * <p>
: * <code>probs<code> 机率阵列的机率和, 必须为 1.0f, 否则会丢出一个
: * <code>RuntimeException</code>
: * @param range 存放各范围大小的阵列
: * @param offset 表示要产生乱数的起始值
: * @param probs 存放各范围机率的阵列
: */
: public static RangeRandom createRangeRandom(int[] range, int offset,
: float[] probs) {
: return new RangeRandom(range, offset, probs);
: } //{END factory} public static RangeRandom createRangeRandom()
: private int getCase() {
: int c = Arrays.binarySearch(probabilityArray, genRandom.nextFloat());
: if( c<0 ) return -(++c);
: else return c;
: } //{END} private int getCase()
如果是要练习Arrays.binarySearch...那不错。
不过事实上:return genRandom.nextInt(probabilityArray.length); 就好了。
写程式,好懂的一行文才是王道。^^
: public int getRand() {
: int caseRange = getCase();
: if( caseRange==0 )
: return offset+genRandom.nextInt(accumulateArray[0]-offset);
: else
: return accumulateArray[caseRange-1]+genRandom.nextInt(
: accumulateArray[caseRange]-accumulateArray[caseRange-1]);
: } //{END} public int getRand()
: protected void setProbArray(float[] probArr) {
: if( probArr.length!= accumulateArray.length )
: throw new RuntimeException("Array size doesn't match.");
: float test = 0f;
: probabilityArray = new float[probArr.length];
: for(int i=0; i<probArr.length; i++) {
: test += probArr[i];
: probabilityArray[i] = test;
: }
: if( test!= 1.0f )
: throw new RuntimeException("Probability doesn't equal to 1.0.");
: } //{END} protected void setProbArray()
: protected void setAccumulateArray(int[] rangeArr) {
: if( rangeArr.length!= probabilityArray.length )
: throw new RuntimeException("Array size doesn't match.");
: int total = offset;
: accumulateArray = new int[rangeArr.length];
: for(int i=0; i<rangeArr.length; i++) {
: total += rangeArr[i];
: accumulateArray[i] = total;
: }
: } //{END} protected void setRangeArray()
public static void main(String[] args)
{
RangeRandom rand = new RangeRandom(new int[]{1,3,2},2,new
float[]{0.2f,0.7f,0.1f});
TreeMap<Integer,Integer> ansMap = new TreeMap<Integer,Integer>() ;
for(int i=0;i<100000;i++)
{
int test = rand.getRand();
if(ansMap.containsKey(test)) ansMap.put(test,ansMap.get(test)+1);
else ansMap.put(test,1);
}
for(Map.Entry<Integer,Integer> ent : ansMap.entrySet())
{
System.out.println("ans["+ent.getKey()+"]="+ent.getValue());
}
}
//给你一个main()不然不能测。
: } //{END class} class RangeRandom
其实这个问题,大家原理应该都是大同小异的。
我是给分布方程式class,产生机率乱数。
也可以给离散数列,设成权阵Array输入,产生机率乱数。
道理都相同的。
--
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 210.85.116.116