unity3d 将浮动拆分为预定的数量,这些数量加起来就是浮动

eagi6jfj  于 2023-03-19  发布在  其他
关注(0)|答案(2)|浏览(121)

我希望创建一个脚本,基本上可以做到以下几点:-

  • 将给定的浮点数拆分为x个浮点数(尤其是拆分为不同的值)
  • 每个值必须以0.05为增量(例如2.65、1.25、18.50)
  • x个浮点数的总和必须等于给定的浮点数

IE它应该看起来像这样:

Total float = 2.50
Amount of splits = 2
New float array = [2, 0.50]

or

Total float = 4.00
Amount of splits = 4
New float array = [1, 2, 0.25, 0.75]

目前我还不能做太多尝试,我一直在努力想一个办法让它发挥作用,但我不确定最好的办法是什么。
编辑:我能够取得一些进展,但我有一个小问题,有时如果我使用的数字太小,它会添加一个0或2在列表中,我不想要的。

public void SplitWinnings()
{
    splitAmounts = new float[loseThreshold - 1];
    while(splitAmounts.Sum() < totalWinAmount)
    {
        int rng = Random.Range(0, splitAmounts.Length);
        splitAmounts[rng] += 0.05f;
        splitAmounts[rng] = Mathf.Round(splitAmounts[rng] * 100f) / 100f;
    }
}
mnemlml8

mnemlml81#

使用Linq SumYour way效率极低!
你可以通过直接跟踪和来大大改进这个问题,大约是原来的3倍,而不必总是一遍又一遍地迭代整个数组,只需要精确地跟踪你在数组中添加或删除的数量:

public void SplitWinnings()
{
    // Keep track of the sum yourself!
    // You already know how much you add each time!
    var sum = 0f;

    splitAmounts = new float[loseThreshold - 1];
    while(sum < totalWinAmount)
    {
        int rng = Random.Range(0, splitAmounts.Length);
        splitAmounts[rng] += minIncrement;
        // also keep track of the sum
        sum += minIncrement;

        float splitFloat = (Mathf.Round(splitAmounts[rng] * 100f) / 100f);

        if (splitFloat > 0)
        {
            // remove the previous value
            sum -= splitAmounts[rng];

            splitAmounts[rng] = splitFloat;

            // track the new value
            sum += splitFloat;
        }
    }
}

但是,您仍然要进行大量的舍入,并且可能以无效的迭代结束,这意味着放弃性能。
我甚至会更进一步,简单地预先计算0.05增量的最大倍数,迭代一个固定的数量-〉你确切地知道你需要预先填充多少元素,然后在int中完成所有剩下的计算。
这样做,我提高了100倍的时间!

public void SplitWinnings()
{
    // calculate how many of your minIncrements you need in total
    var totalMultiples = Mathf.RoundToInt(totalWinAmount / minIncrement);
    // while iterating will keep track of how many multiples you have remaining
    var remainingMultiples = totalMultiples;

    // Not sure why but you seem to require -1 here
    var splitCount = loseThreshold - 1;
    splitAmounts = new float[splitCount];
    
    // instead of while have a fixed amount of iterations
    // namely exactly for all return elements except the last one
    for(var i = 0; i < splitCount - 1; i++)
    { 
        // reducing the remaining array elements => save up at least 1 multiple for each array element
        var maxMultiples = remainingMultiples - (splitCount - i);
        // use at least one multiple per element
        // have to add +1 again since upper bound for int is exclusive but we want to use it up
        var multiples = Random.Range(1, maxMultiples + 1);
        
        // after calculating the multiples in int multiply again by the minIncrement to get according float value
        splitAmounts[i] = multiples * minIncrement;
        
        // and reduce the remaining multiples accordingly
        remainingMultiples -= multiples;
    }
    
    // The last item is just filled with whatever is left
    splitAmounts[splitCount - 1] = remainingMultiples * minIncrement;
}

参见.Net Fiddle进行比较

djmepvbi

djmepvbi2#

正如@Jeroen Mostert所提到的,这适用于较低数量的拆分值。但实际上正是我所寻找的。:)

public void SplitWinnings()
{
    splitAmounts = new float[loseThreshold - 1];
    while(splitAmounts.Sum() < totalWinAmount)
    {
        int rng = Random.Range(0, splitAmounts.Length);
        splitAmounts[rng] += minIncrement;

        float splitFloat = (Mathf.Round(splitAmounts[rng] * 100f) / 100f);

        if (splitFloat > 0)
        {
            splitAmounts[rng] = splitFloat;
        }
    }
}

相关问题