1

double型の既知の値の配列に一種のリップルを追加したいと思います。Random.Next / Random.NextDouble()の動作が異なるため、この点を指摘します。

このタスクを最もよく達成するにはどうすればよいですか?

配列に
List<double> arr = new List<double>() { 40, 40, 40, 40 ..... };
20個の値があり、20個の値が40の平均値であり、合計が800であるとすると、簡単になります。

この方法の後も、全体の合計は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];

最後に生成された値が重ならないように考慮されています。さらに、リストに2つの値しか含まれていない場合の例外。は魔法のqty=1ように見えるかもしれませんが、オブジェクトbArrayが実際にどのように見えるかを示しています。とにかく全体の考えは明確だと思います。

4

4 に答える 4

5

これを行う1つの方法は、0から1(排他的)までのN個の乱数を生成することです。それらを合計します。次に、各数値を合計で割ります。これで、合計が1になるN個の乱数のリストができました。次に、これらの各数値に目的の合計を掛けて、最終的な配列に入る数値を取得します。

値を+/-あるパーセンテージにしたい場合は、を使用Random.Nextして、ある範囲内の乱数を生成し、それらを合計します。次に、合計で割って、合計が1になる数値のリストを取得します。最後のステップは同じです。

于 2012-04-16T17:04:02.417 に答える
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;
于 2012-04-16T17:05:40.843 に答える
1

以下は私の解決策です。

基本的に、各値を指定されたパーセンテージで「ジッター」し、元の合計と「ジッター」合計の差をチェックします。最終的な合計を元の合計と一致させるために、各「ジッター」値に一定の金額を追加します。

各値にフラットな量を追加すると、各値の実際の異常率が歪む可能性があるため、これは数学的な観点からは優れた解決策ではないと思います。意図した収差の割合を維持するように、値のセット全体に余りを適用するより数学的に正しい方法がおそらくありますが、これを行うには数回のパスが必要になると思いますが、このソリューションは設定された数のパスで完了しますパスします。

// 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];
}
于 2012-04-16T17:15:38.640 に答える
0

連続する数値の各ステップで乱数(ゼロに関して対称)を選択します。次に、それを最初に加算し、2番目から減算します。

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

これにより、配列要素がすべて変更されている間、配列の合計が同じままであることが保証されます(モジュロ浮動小数点エラー)。

于 2012-04-16T17:26:23.373 に答える