Remove floating points from map generation
Removes all use of floating point from the RaMapGenerator map generator and its dependencies. Floating point behavior is potentially non-portable across client hardware. Removing them should make the map generation logic consistent even across clients with different floating point hardware or compiler behavior. This may be useful for sync-safe multiplayer map generation where clients independently generate the map from settings. Most previously fractional public-facing settings are now represented as numbers out of 1000, with some exceptions using 1000000. Most internal logic which relies on fixed-point concepts now uses 1024ths, though some floating point mechanisms have been replaced with alternative discrete approximations (e.g. gaussian to binomial).
This commit is contained in:
committed by
Gustas Kažukauskas
parent
04e9cef38e
commit
037326024b
@@ -11,7 +11,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.Support
|
||||
{
|
||||
@@ -35,7 +34,7 @@ namespace OpenRA.Support
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Produces an unsigned integer between -0x80000000 and 0x7fffffff inclusive.
|
||||
/// Produces a random unsigned 32-bit integer.
|
||||
/// </summary>
|
||||
public uint NextUint()
|
||||
{
|
||||
@@ -54,7 +53,7 @@ namespace OpenRA.Support
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Produces an unsigned integer between -0x80000000 and 0x7fffffff inclusive.
|
||||
/// Produces a random unsigned 64-bit integer.
|
||||
/// </summary>
|
||||
public ulong NextUlong()
|
||||
{
|
||||
@@ -98,48 +97,32 @@ namespace OpenRA.Support
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Produces uniformally distributed random floats between 0 inclusive and 1 exclusive.
|
||||
/// Note that whilst floats are 32-bit (23-bit mantissa), each output contains exactly 23 bits of entropy.
|
||||
/// Pick a random index from a list of weights.
|
||||
/// </summary>
|
||||
public float NextFloatExclusive()
|
||||
public int PickWeighted(IReadOnlyList<int> weights)
|
||||
{
|
||||
return (NextUint() & 0x7fffff) / (float)0x800000;
|
||||
}
|
||||
ulong total = 0;
|
||||
foreach (var weight in weights)
|
||||
{
|
||||
if (weight < 0)
|
||||
throw new ArgumentException("Found a negative weight.");
|
||||
total += (ulong)weight;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Produces uniformally distributed random doubles between 0 inclusive and 1 exclusive.
|
||||
/// Note that whilst doubles are 64-bit (52-bit mantissa), each output contains exactly 52 bits of entropy.
|
||||
/// </summary>
|
||||
public double NextDoubleExclusive()
|
||||
{
|
||||
return (NextUlong() & 0xfffffffffffffL) / (double)0x10000000000000L;
|
||||
}
|
||||
if (total == 0)
|
||||
return Next(0, weights.Count);
|
||||
|
||||
/// <summary>
|
||||
/// Pick a random an index from a list of weights.
|
||||
/// </summary>
|
||||
public int PickWeighted(IReadOnlyList<float> weights)
|
||||
{
|
||||
var total = weights.Sum();
|
||||
var spin = NextFloatExclusive() * total;
|
||||
var spin = NextUlong() % total;
|
||||
int i;
|
||||
float acc = 0;
|
||||
ulong acc = 0;
|
||||
for (i = 0; i < weights.Count; i++)
|
||||
{
|
||||
acc += weights[i];
|
||||
acc += (ulong)weights[i];
|
||||
if (spin < acc)
|
||||
return i;
|
||||
}
|
||||
|
||||
// This might be possible due to floating point precision loss
|
||||
// (in rare cases). Or we might have been given rubbish
|
||||
// weights. Return anything > 0.
|
||||
for (i = 0; i < weights.Count; i++)
|
||||
if (weights[i] > 0)
|
||||
return i;
|
||||
|
||||
// All <= 0!
|
||||
return Next(0, weights.Count);
|
||||
throw new InvalidOperationException("unreachable");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user