作者AI3767 (AI3767)
看板java
標題Re: [問題] 亂數產生一個矩陣
時間Thu Mar 16 01:59:49 2006
※ 引述《zanyking (遙遠的旅人)》之銘言:
: 是的,我知道probArr是先指向傳入的陣列等到第一個set方法時可以用來比較長度。
: 所以我才會覺得,這不是一個好方法。
: 你應該要直接比較建構子傳入的兩個陣列長度是否相同,而不是之後才在set方法中比。
: 而且,如果建構子中會呼叫class本身的非static 也非private方法的話,就物件設計
: 來看是很危險的:
: 1.拿去用的人通常很難正確的修改protected方法。
: 2.在一個多型的架構中你是無法猜測物件是如何被建構的。而現在,你的物件不但不
: 知道如何被建構,還有可能在初始化時跟某個不知何時被override掉的方法交配出
: 更加未知的物件。
: 3.如果你的建構子複雜到必須用一堆方法來結構他...寫一個Helper當傳入參數吧。
這個我能理解......只是.......
java本身很多的原始碼就是這樣子寫的, 例如 JTable
它的建構式去呼叫了 setColumnModel, setSelectionModel, setModel 等方法
我想這麼做的好處, 也是讓override時, 可以使用更新的method, 這樣彈性大
如果寫壞了, 那是programmer應該去測試並解決的
: 所以,還是照你一開始說的,避免誤用比較好吧。
: 與其override,不如丟一個新的Helper進去改變他的行為。
: JAVA OOP裡有句名言(不可考):
: "除了實做介面外,通常會被override掉的方法只存在在Object裡。"
: : 若是直接給定的話, 的確是難用的, 我的設想是在
: : 使用者應該會去維護一個範圍array,如rArr,以及對映的機率array,如pArr
: : 然後在要用時, 才去createRangeRandom(rArr,0,pArr)
: : 而上面您給的例子, 可以是
: : int[] rangs = {4, 1, 1};
: : float probs = {0.4f, 0.2f, 0.3}; //其實會exception, 因為總和不為1.0f
: 所以你知道有多難用了...我有檢查過可是還是miss掉了。
: 人老了,唉~~~
呵...這是希望那個probArray的內容, 是使用者要好好維護的,不一定要手動
必要時應該要使用函式去想辦法算出機率,
您的程式碼我有看過了, 是較為彈性的做法, 所以,
我也將程式改寫了, 同時附一個測試檔...
在測試檔內比較能看出用法 ><
呃...當然程式碼就變冗長很多了 Orz
: 傳入的rangs我覺得如果要解釋給User聽...大概User會先把我幹掉。
: 可以的話,不要傳機率進來,直接傳純量的int權重值。
: 我之前在寫我的curve版時之所以不用機率(最後才算),是因為考慮可能有捨位
: 誤差的問題在,所以可以避開float、double我都會盡可能避開,直到最後關頭
: 才用它。
: 權重陣列也是一樣的而且更方便,你可以:
: /**
: *宣布誰中X
: *
: */
: target = new string[]{"qrrt1","godfat","AI3767","zanyking","psmonkey"};
: weight = new int[]{1,2,3,4,5};//中X機率是....
: sumWeight = new int[]{1,3,6,10,15};//算出來的累加權陣
: int randInt = random.getInt(15);//命運的一刻
: for(int i=0;i<target.length;i++)
: {
: if(randInt<=sumWeight[i])
: {
: System.out.println("The Winner is:"+target[i]);//宣布中X人
: break;
: }
: }
: 感覺會更直觀,詳細作法請trace我的source code。
嗯嗯...就是這裡, 因為用循序找序,我感覺效率上可能不太好
所以改用Java提供的 binaraySearch 來試圖改進
------
程式碼
------
檔案: ProbProvider.java
package tw.edu.ccu.cs.ailab;
public interface ProbProvider {
/** 回傳整個要提供機率元素的數量. */
public int getSize();
/** 回傳在<code>rangeIndex</code>位置相對於其他位置的機率值. 不必小於1. */
public float getProbability(int rangeIndex);
} //{END interface} interface ProbProvider
檔案: RangeRandom.java
package tw.edu.ccu.cs.ailab;
import java.util.Arrays;
import java.util.Random;
public class RangeRandom {
private Random genRandom;
private int[] rangeAccArray;
private int offset;
private float[] probabilityAccArray;
private float totalProb = 1f;
/** 利用 <code>rangeArr</code> 陣列所設定的各個範圍大小, 相對同個索引位置的
* <code>relProbArr</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%.
* <br>相對機率總和不必為1.0, 因為是表示相對關係的機率.
* @param rangeArr 存放各範圍大小的陣列
* @param off 表示要產生亂數的起始值
* @param relProbArr 存放各範圍相對機率的陣列
*/
public RangeRandom(int[] rangeArr, int off, float[] relProbArr) {
offset = off;
define(rangeArr, relProbArr);
genRandom = new Random();
} //{END constructor}
public int[] getRangeAccArray() { return rangeAccArray; }
/** 使用由使用者提供相對機率的實作, 來建立相對機率陣列.
* 其實不必提供這個method. 這些應由使用者自行處理 Orz.
*/
public static float[] buildProbArray(ProbProvider probProv) {
int size = probProv.getSize();
float[] probArray = new float[size];
for(int i=0; i<size; i++)
probArray[i] = probProv.getProbability(i);
return probArray;
} //{END} public static float[] buildProbArray()
/** 設定範圍陣列和相對機率陣列. 兩者長度須一致. */
public void define(int[] rangeArr, float[] relProbArr) {
if( relProbArr.length!=rangeArr.length )
throw new RuntimeException("Array size doesn't match.");
rangeAccArray = null;
probabilityAccArray = null;
setRangeArray(rangeArr);
setProbArray(relProbArr);
} //{END} public void define()
private int getCase() {
int c = Arrays.binarySearch(
probabilityAccArray, genRandom.nextFloat()*totalProb);
if( c<0 ) return -(++c);
else return c;
} //{END} private int getCase()
public float[] getProbAccArray() { return probabilityAccArray; }
public int getRand() {
int caseRange = getCase();
if( caseRange==0 )
return offset+genRandom.nextInt(rangeAccArray[0]-offset);
else
return rangeAccArray[caseRange-1]+genRandom.nextInt(
rangeAccArray[caseRange]-rangeAccArray[caseRange-1]);
} //{END} public int getRand()
/** 重新定義相對機率. <code>relProbArr</code> 的長度必須和先前所定義的範圍陣列
* 長度須一致.
* @relProbArr 當為<code>null</code>時會丟出Exception
*/
public void setProbArray(float[] relProbArr) {
if( rangeAccArray!=null && relProbArr.length!=rangeAccArray.length )
throw new RuntimeException("Array size doesn't match.");
float test = 0f;
probabilityAccArray = new float[relProbArr.length];
for(int i=0; i<relProbArr.length; i++) {
test += relProbArr[i];
probabilityAccArray[i] = test;
}
totalProb = test;
} //{END} protected void setProbArray()
/** 重新定義範圍. <code>rangeArr</code> 的長度必須和先前所定義的機率陣列
* 長度須一致.
* @rangeArr 當為<code>null</code>時會丟出Exception
*/
public void setRangeArray(int[] rangeArr) {
if( probabilityAccArray!=null &&
rangeArr.length!= probabilityAccArray.length )
throw new RuntimeException("Array size doesn't match.");
int total = offset;
rangeAccArray = new int[rangeArr.length];
for(int i=0; i<rangeArr.length; i++) {
total += rangeArr[i];
rangeAccArray[i] = total;
}
} //{END} protected void setRangeArray()
} //{END class} class RangeRandom
測試執行檔: TestRand.java
import tw.edu.ccu.cs.ailab.RangeRandom;
import tw.edu.ccu.cs.ailab.ProbProvider;
class TestRand implements ProbProvider {
int[] rangeArray;
float[] probArr;
public static void main(String[] arg) {
int offset = 0;
int testCount = 1000;
int[] rangeArr = {11, 7, 3, 20};
TestRand tr = new TestRand(rangeArr);
tr.test1(offset, testCount);
System.out.println();
rangeArr = new int[1000];
for(int i=0; i<1000; i++) rangeArr[i] = 1;
tr = new TestRand(rangeArr);
tr.test2(offset, testCount);
} //{END main}
TestRand(int[] rangeArr) {
rangeArray = rangeArr;
}
void test1(int offset, int testCount) {
probArr = new float[]{0.4f, 0.2f, 0.3f, 0.1f};
mainTest(probArr, offset, testCount);
}
void test2(int offset, int testCount) {
probArr = RangeRandom.buildProbArray(this);
mainTest(probArr, offset, testCount);
}
void mainTest(float[] probArr, int offset, int testCount) {
RangeRandom rr = new RangeRandom(rangeArray,offset,probArr);
int[] accArr = rr.getRangeAccArray();
float tot = rr.getProbAccArray()[accArr.length-1];
for(int i=0; i<probArr.length; i++)
System.out.println("P["+i+"]: \t"+probArr[i]/tot);
int[] counter = new int[rangeArray.length];
for(int i=0; i<testCount; i++) {
int d = rr.getRand();
if( d<accArr[0] && d>=0 ) counter[0]++;
else
for(int j=rangeArray.length-1; j>0; j--)
if( d<accArr[j] && d>=accArr[j-1]) {
counter[j]++;
break;
}
} //{END} for(every rand)
System.out.println(offset+"~"+accArr[1]+": \t"+counter[0]);
for(int i=1; i<counter.length;i++)
System.out.println(accArr[i-1]+"~"+accArr[i]+": \t"+counter[i]);
}
// * ProbProvider * //
public int getSize() {
if( rangeArray==null ) return -1;
return rangeArray.length;
} //{END} public int getSize()
public float getProbability(int rangeInd) {
return 1.0f/(rangeInd+1);
} //{END} public float getProbability(
} //{END class} class TestRand implements ProbProvider
--
白月光 心裡某個地方 (@ @)
那麼亮 卻那麼冰涼 (T T)
每個人 都有一斷背山 (囧)
想隱藏 卻欲蓋彌彰 (= =)
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 140.123.219.115
※ 編輯: AI3767 來自: 140.123.219.115 (03/16 02:43)