Re: [問題] 亂數產生一個矩陣

看板java作者 (AI3767)時間18年前 (2006/03/16 01:34), 編輯推噓0(000)
留言0則, 0人參與, 最新討論串14/15 (看更多)
※ 引述《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)
文章代碼(AID): #14650f04 (java)
討論串 (同標題文章)
文章代碼(AID): #14650f04 (java)