Fluent-Random-Picker
Fluent-Random-Picker copied to clipboard
Weights using long
Hey,
Is it possible to extend weights to support long, lookg like at the moment they only support int?
❤️
Hey,
I limited the weights to int in the beginning, because Fluent Random Picker uses algorithms that sum up all the weights internally.
If the int weights are Int32.MaxValue and Int32.MaxValue, the sum can't be stored as an int. So I use long for the sum internally at the moment.
If I'd allow long weights and if they are Int64.MaxValue and Int64.MaxValue, the sum can't be stored as a long. I'd need a larger data type then internally...
2 ways are probably possible on my site:
- Replacing the algorithm that sums up the numbers (at least when the weights are longs) with one that works differently.
- .Net7 (will be available in about a month) offers a new Data type (Int128), which I could use to calculate a sum of longs. But this would only work in projects that are targeting .Net7 or higher.
Which .Net version are you targeting?
I'll take a closer look at this in the future.
Hey,
Makes sense, you /could/ use BigInteger to sum the values. Tho it might be slow.
I'm currently targeting .net 7 rc1.
Right now I'm just casting to int so I'm not hindered, but what I'm using it for is figuring out in my game 'who' should hit.
Your library just makes mundane stuff easier :D
var entity = Out.Of()
.Value(EntityType.Player).WithWeight((int)playerSpeed)
.AndValue(EntityType.Monster).WithWeight((int)monsterSpeed)
.PickOne();
Notes for me:
-
SortingBasedWeightedLeftShuffle
would break with longs because all results are 1 at some point.
Math.Pow(0.9999, 1/(double)int.MaxValue) // = 0.99999999999995348165526820594095624983310699462891
Math.Pow(0.9999, 1/(double)long.MaxValue) // = 1.00000000000000000000000000000000000000000000000000
Math.Pow(0.9999, 1/((double)long.MaxValue/10)) // = 1.00000000000000000000000000000000000000000000000000
Math.Pow(0.9999, 1/((double)long.MaxValue/1_000_000)) // = 1.00000000000000000000000000000000000000000000000000
Math.Pow(0.9999, 1/((double)long.MaxValue/10_000_000)); // = 0.99999999999999988897769753748434595763683319091797
So, maybe, there needs to be a fallback like Math.Pow(0.9999, 10_000_000/(double)n);
for larger numbers.
Maybe, a fallback should already be there for ints, because for ~0,000001% of the weights (higher if we would allow long weights), it does not even make a difference, whether they are int.MaxValue
or int.MaxValue / 10
(edge case):
Math.Pow(0.99999999, 1/(double)int.MaxValue) // = 1.00000000000000000000000000000000000000000000000000
Math.Pow(0.99999999, 1/((double)int.MaxValue / 10)) // = 1.00000000000000000000000000000000000000000000000000
BTW: Random.NextDouble being exactly 0 could also be problematic as the result is always 0...
-
DefaultPicker
would break because it calculates the sum resulting in a possible overflow (solvable with Int128 from .Net7 or BigInteger) - Everything else should still work with longs.