Refactor civilization flow reward calculations for improved accuracy and performance

This commit is contained in:
Kirill
2026-10-08 21:25:39 +03:00
parent c42940369a
commit 459fbb2a4d
3 changed files with 683 additions and 0 deletions
+21
View File
@@ -303,6 +303,27 @@ static func split_arrays(remainders: Dictionary, key: String, count: Variant, id
static func accumulate_rate(remainders: Dictionary, key: String, count: Variant, probability: Variant) -> Variant:
# Reward rates are floats while populations are exact whole values. Keep
# the product as quotient plus fractional carry instead of constructing an
# intermediate Exact Value and flooring it again.
if probability is float and is_finite(probability) and probability >= 0.0 and (count is int or (count is E.Value and count.fraction == 0.0)) and E.ge(count, 0):
var terms: Array = E.parts(probability)
if terms[2] > 0:
var population: Array = E._blocks(count)[0]
var whole_product: Array = E.Big.multiply(population, terms[0])
var qr: Array = E.Big.divmod(whole_product, terms[1])
var fractional: float = E._fraction_ratio(qr[1], terms[1])
var carry: float = E.approx(remainders.get(key, 0))
if carry >= 0.0 and carry < 1.0:
if qr[1] == [0]:
remainders[key] = carry
return E._compose(qr[0])
fractional += carry
if fractional > 0.5 and absf(fractional - roundf(fractional)) <= 1e-12:
fractional = roundf(fractional)
var extra: int = floori(fractional)
remainders[key] = fractional - extra
return E.add(E._compose(qr[0]), extra)
var product: Variant = E.multiply(count, E.maximum(0, probability))
var carry: float = E.approx(remainders.get(key, 0))
if carry >= 0.0 and carry < 1.0 and E.ge(product, 0):