2012-04-16 51 views
1

我想添加一種類型的已知值的一組紋波。我指出,因爲Random.Next/Random.NextDouble()行爲不同。在給定值附近得到一個隨機的異常

我該如何最好地完成這項任務?

設說我有陣列中20個值,其被平均上量40,總的800
List<double> arr = new List<double>() { 40, 40, 40, 40 ..... };
20個值,使之更容易。

經過這種方法,我想整體總計仍然保持800,但每個單獨的值應該被修改。值應該是正值,因爲它們是total+=i之後添加的。

到目前爲止,使用給定數量值的百分比解決了這個問題。
1.0/20 = 0.05, then multiplicate that with the total and the iteration number. Then subtract the result from the remainder. Finally i just return a sort by new Guid()

正如你已經看到的,這種方法只有一點點了不起,而只有5-20個值。在我今天的情況下,這個數組需要站在500-2000的值(每個值爲0.2-0.05%)。

相反,我想有一個派生或這樣的,以+ 40%的+ -x%作爲基礎的變形。或者,也許更好,在數組中的任何單個值上加上-x%)。

[更新]

我將基於對這個問題的答覆更新添加的問題。

Random rnd = new Random(); 
    List<double> ripple = new List<double>(); 

    int qty = bArray.Count(); 
    double diff = last.Value - first.Value; 

    if (qty == 1) 
    { 
     double linearAvg = (diff/qty)/2; 
     ripple.Add(linearAvg); 
    } 
    else 
    { 
     double[] rndarr = new double[qty]; 

     for (int i = 0; i < qty; i++) 
      rndarr[i] = rnd.NextDouble(); 

     double rndArrSum = rndarr.Sum(); 

     for (int i = 0; i < qty; i++) 
      rndarr[i] /= rndArrSum; 

     for (int i = 0; i < qty; i++) 
      ripple.Add(diff * rndarr[i]); 
    } 

    double valueOverall = first.Value; 
    for (int i = (qty > 1) ? 1 : 0; i < qty; i++) 
     valueOverall += ripple[i]; 

允許上次生成的值不重疊。另外,列表只包含兩個值時是一個例外。 qty=1可能看起來很神奇,但它指的是對象bArray在實際中的樣子。無論如何,我認爲整個想法很清楚。

+2

你能隨機擾動只是第N-1的值,然後進行最後的值所需的值,使總出來800? – mellamokb 2012-04-16 16:56:35

+1

@mellamokb,聽起來像它會不成比例地歪曲最後的價值。 – 2012-04-16 17:01:27

+0

@ Dr.Wily'sApprentice:的確如此,我測試了:)另一個想法:擾亂所有的值,然後攤開它是所有號碼中關閉的數量。 – mellamokb 2012-04-16 17:02:54

回答

5

你可以這樣做的一種方法是生成0到1之間的N個隨機數(獨佔)。總結他們。然後將每個數字除以總和。你現在有一個N個隨機數列表,總和爲1.現在,將這些數字乘以你想要的總和,得到將進入最終數組的數字。

如果您希望您的值爲+/-某個百分比,那麼請使用Random.Next生成某個範圍內的隨機數並對它們進行求和。然後除以總數得到總和爲1的數字列表。最後一步是相同的。

+0

啊哈! crz,謝謝!明顯..現在當你說出來:)。它會自動地解決第二種方法。我在幾個小時內嘗試了一下。 – Independent 2012-04-16 17:12:47

+0

更新瞭解決方案的一部分, – Independent 2012-04-16 20:27:29

2

另一種方法是循環訪問數組,並按百分比值擾動。一旦完成,計算總額有多遠,並在所有數字中均等地添加盤盈數額。以下是一些示例代碼:

var test = Enumerable.Repeat<double>(40, 100).ToArray(); 
var percent = 0.5d; 

var rand = new Random(); 
var expectedTotal = test.Sum(); 
var currentTotal = 0d; 
var numCount = test.Count(); 

for (var i = 0; i < numCount; i++) 
{ 
    var num = test[i]; 
    var range = num * percent * 2; 

    var newNum = num + (rand.NextDouble() - 0.5) * (range); 
    currentTotal += newNum; 
    test[i] = newNum; 
} 

var overage = (expectedTotal - currentTotal); 

for (var i = 0; i < numCount; i++) 
    test[i] += overage/numCount; 
1

以下是我的解決方案。

基本上,它會以某個特定的百分比「抖動」每個值,然後檢查原始總數和「抖動」總數之間的差異。爲了使最終總計與原始總額相匹配,它會爲每個「抖動」值添加一個固定金額。

我覺得這是不是從數學的角度很好的解決方案,因爲我認爲加平量的每個值可能會扭曲abberation的每個值的真實比例。有可能是一個數學上更正確的方式來應用跨組值的剩餘部分以這樣的方式來保持abberation的預期百分比,但我想,這樣做會需要幾個通行證,而這個解決方案中的一組數字完成經過。

// prepare data 
double[] values = new double[20]; 
for (int i = 0; i < values.Length; i++) 
{ 
    values[i] = 40.0; 
} 

// get the original total 
double originalTotal = 0.0; 
for (int i = 0; i < values.Length; i++) 
{ 
    originalTotal += values[i]; 
} 

// specify an abberation percentage 
double x = 0.05; 

// jitter each value +/- the abberation percentage 
// also capture the total of the jittered values 
Random rng = new Random(); 
double intermediateTotal = 0.0; 
for (int i = 0; i < values.Length; i++) 
{ 
    values[i] += values[i] * (rng.NextDouble() - 0.5) * (2.0 * x); 
    intermediateTotal += values[i]; 
} 

// calculate the difference between the original total and the current total 
double remainder = originalTotal - intermediateTotal; 

// add a flat amount to each value to make the totals match 
double offset = remainder/values.Length; 
for (int i = 0; i < values.Length; i++) 
{ 
    values[i] += offset; 
} 

// calculate the final total to verify that it matches the original total 
double finalTotal = 0.0; 
for (int i = 0; i < values.Length; i++) 
{ 
    finalTotal += values[i]; 
} 
+0

哈哈,我們有完全相同的解決方案,偉大的思想家都認爲:) – mellamokb 2012-04-16 17:17:13

0

選擇一個隨機數(圍繞零對稱)爲連續號碼之間的每個步驟。然後,將其添加到所述第一,和從第二減去它:

for(int i=1; i<length; i++) { 
    dx = (rng.NextDouble() - 0.5) * scale; 
    arr[i-1] += dx; 
    arr[i] -= dx; 
} 

這應該確保該數組的總和保持不變(模浮點錯誤),而該陣列的元件的所有修改。