繁体   English   中英

在javascript中,如何在控制总金额的同时,向用户的余额添加随机数?

[英]In javascript, how do I add a random amount to a user's balance while controlling how much gets given total?

我正在尝试使用户执行某项操作的位置达到2到100个单位。 但是,对于每1000个请求,我希望它总共增加3,500个单位。

这是我用来向用户随机添加不同金额的代码:

if (Math.floor(Math.random() * 1000) + 1 === 900) {
    //db call adding 100
}
else if (Math.floor(Math.random() * 100) + 1 === 90)  {
    //db call adding 40
}
else if (Math.floor(Math.random() * 30) + 1 === 20)  {
    //db call adding 10
}
else if (Math.floor(Math.random() * 5) + 1 === 4)  {
    //db call adding 5
}
else {
    //db call adding 2
}

如果我的数学是正确的,那么这应该平均每1,000个调用大约4,332个单位。 但显然情况会有所不同,我不希望那样。 我还希望它添加随机数量,因为示例中添加的单位是任意的。

编辑:伙计们,吉尔多是对的,我只想拥有3,500个单位,并在1,000个请求之内送出它们。 甚至也不必完全达到最大值3500(我可能已经指定了)。 重要的是,我不会给用户太多的东西,而同时为他们创造机会赢得更大的收益。

这是我现在设置的,它运行良好,并且通过一些调整会更好地工作:

通话以外:

var remaining = 150;
var count = 0;

通话内:

    count += 1;
    if (count === 100) {
        remaining = 150;
        count = 0;
    }

    if (Math.floor(Math.random() * 30) + 1 === 20) {
        var addAmount = Math.floor(Math.random() * 85) + 15;
        if (addAmount <= remaining) {
            remaining -= addAmount;
            //db call adding addAmount + 2
        }
        else {
            //db call adding 2
        }
    }
    else if (Math.floor(Math.random() * 5) + 1 === 4) {
        var addAmount1 = Math.floor(Math.random() * 10) + 1;
        if (addAmount1 <= remaining) {
            remaining -= addAmount1;
            //db call adding addAmount1 + 2

        }
        else {
            //db call adding 2
        }
    }
    else {
        //db call adding 2
    } 

我想我应该弄清楚,我想要一个很小的“随机”数。 那是the头的一部分,在那儿您获得更大金额的可能性很小。

正如我评论过的,1,000个2到100之间的随机数加起来等于3500,这是平均数3.5,这与2到100之间的随机选择不一致。您必须将2和3的值几乎全部要实现这一目标,实际上最多只能有几个。 几乎没有随机的东西。 因此,要使它甚至是随机的和可行的,您必须选择比3500大得多的总数。 2至100之间的1000个随机总数将更像51,000。

此外,您不能以真正随机的方式动态生成每个数字并保证特定的总数。 保证结果的主要方法是预先分配随机数,这些总数加到已知的总数中,然后从预先分配的方案中随机选择每个数字,然后从选择中删除以供将来选择。

如果您偏离总数,也可以尝试保持连续的总数并偏向随机性,但是这样做,最后一组数字可能甚至不必接近于随机数,才能始终如一地达到总数。

如果您重置总数以支持实际随机性(例如,达到51,000),那么可以使用的方案将是在2至100之间预先分配500个随机数的数组,然后再添加500个随机数的补集。 这保证了51平均数。 然后,您可以从预先分配的数组中随机选择每个数字,然后将其从数组中删除,这样就不会再次选择它。 我可以添加代码以在一秒钟内完成此操作。

function RandResults(low, high, qty) {
    var results = new Array(qty);
    var limit = qty/2;
    var avg = (low + high) / 2;
    for (var i = 0; i < limit; i++) {
        results[i] = Math.floor((Math.random() * (high - low)) + low);
        // 
        results[qty - i - 1] = (2 * avg) - results[i];
    }
    this.results = results;
}

RandResults.prototype.getRand = function() {
    if (!this.results.length) {
        throw new Error("getRand() called, but results are empty");
    }
    var randIndex = Math.floor(Math.random() * this.results.length);
    var value = this.results[randIndex];
    this.results.splice(randIndex, 1);
    return value;
}

RandResults.prototype.getRemaining = function() {
    return this.results.length;
}


var randObj = new RandResults(2, 100, 1000);

// get next single random value
if (randObj.getRemaining()) {
   var randomValue = randObj.getRand();
}

工作演示,用于真正随机选择的数字加起来为51,000(这是2到100之间的1,000个随机值应加起来的值): http : //jsfiddle.net/jfriend00/wga26n7p/


如果需要以下内容:1,000个数字加起来为3500,并从2到100(含)范围内选择,其中大多数数字为2或3,但有时最多为100,那么就不一样了问题。 我不会真正使用随机这个词来形容它,因为它是一个高度偏向的选择

这是一种方法。 它会生成2至100之间的1,000个随机数,并跟踪总数。 然后,通过随机选择的值并将其递减,直到总数降低到3500,才校正随机数以达到正确的总数。 您可以在这里看到它的工作: http : //jsfiddle.net/jfriend00/m4ouonj4/

代码的主要部分是这样的:

function RandResults(low, high, qty, total) {
    var results = new Array(qty);
    var runningTotal = 0, correction, index, trial;
    for (var i = 0; i < qty; i++) {
        runningTotal += results[i] = Math.floor((Math.random() * (high - low)) + low);
    }
    // now, correct to hit the total
    if (runningTotal > total) {
        correction = -1;
    } else if (runningTotal < total) {
        correction = 1;
    }
    // loop until we've hit the total
    // randomly select a value to apply the correction to
    while (runningTotal !== total) {
        index = Math.floor(Math.random() * qty);
        trial = results[index] + correction;
        if (trial >= low && trial <= high) {
            results[index] = trial;
            runningTotal += correction;
        }
    }

    this.results = results;
}

这符合一个偏共有3,500 2和100之间的所有数字的目标,虽然的概率2在这个方案是非常高,大概的100在这个方案几乎是不存在的。


而且,这是一个加权随机生成器,其总和为精确的总数。 这使用三次加权方案来支持较低的数字(一个数字的大概值随该数字的立方下降),然后在生成随机数之后,一种校正算法将随机校正应用于这些数字以使总数得出完全符合规定。 一个有效的演示代码在这里: http : //jsfiddle.net/jfriend00/g6mds8rr/

function RandResults(low, high, numPicks, total) {
    var avg = total / numPicks;
    var i, j;
    // calculate probabilities for each value
    // by trial and error, we found that a cubic weighting
    // gives an approximately correct sub-total that can then
    // be corrected to the exact total
    var numBuckets = high - low + 1;
    var item;
    var probabilities = [];
    for (i = 0; i < numBuckets; i++) {
        item = low + i;
        probabilities[i] = avg / (item * item * item);
    }

    // now using those probabilities, create a steps array
    var sum = 0;
    var steps = probabilities.map(function(item) {
        sum += item;
        return sum;
    });

    // now generate a random number and find what
    // index it belongs to in the steps array
    // and use that as our pick
    var runningTotal = 0, rand;
    var picks = [], pick, stepsLen = steps.length;
    for (i = 0; i < numPicks; i++) {
        rand = Math.random() * sum;
        for (j = 0; j < stepsLen; j++) {
            if (steps[j] >= rand) {
                pick = j + low;
                picks.push(pick);
                runningTotal += pick;
                break;
            }
        }
    }

    var correction;
    // now run our correction algorithm to hit the total exactly
    if (runningTotal > total) {
        correction = -1;
    } else if (runningTotal < total) {
        correction = 1;
    }    

    // loop until we've hit the total
    // randomly select a value to apply the correction to
    while (runningTotal !== total) {
        index = Math.floor(Math.random() * numPicks);
        trial = picks[index] + correction;
        if (trial >= low && trial <= high) {
            picks[index] = trial;
            runningTotal += correction;
        }
    }
    this.results = picks;    
}

RandResults.prototype.getRand = function() {
    if (!this.results.length) {
        throw new Error("getRand() called, but results are empty");
    }
    return this.results.pop();
}

RandResults.prototype.getAllRand = function() {
    if (!this.results.length) {
        throw new Error("getAllRand() called, but results are empty");
    }
    var r = this.results;
    this.results = [];
    return r;
}


RandResults.prototype.getRemaining = function() {
    return this.results.length;
}

正如一些评论所指出的那样……问题中的数字不太有意义,但是从概念上讲,有两种方法:及时或提前进行动态计算。

要及时计算:

您可以维护一个remaining变量,该变量跟踪remaining的3500个变量。 每次当您随机分配一些单位时,请从remaining的数字中减去该数字,直到其变为0。

另外,要确保每次至少给出2个单位,您可以从remaining = 1500开始,然后每次random + 2给出random + 2单位。

为了防止在1000次赠予之后仍然剩余余额的情况,您可能需要添加一些逻辑以在最后几次更积极地分配单位。 但是,它将导致不太随机的结果。

要提前计算:

[2, 100] 2,100 [2, 100]生成具有1000个值的随机列表,总和为3500。然后对列表进行混洗。 每次您要提供一些单位时,请选择数组中的下一项。 1000次捐赠后,以相同的方式生成另一个列表。 这样,您可以获得更好的随机结果。

请注意,这两种方法都需要某种共享状态,在多线程环境中需要谨慎处理。

希望这些想法有所帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM