sots-engine/src/game/sim/numeric.h

48 lines
1.8 KiB
C++

// Small numeric helpers shared by the sim formulas.
//
// The original engine converts floating point to integer by truncation toward zero
// (the MSVC float-to-long helper); `Ftol`/`Ftoi64` reproduce that so every rounding site
// in this module is explicit about which conversion it performs.
#pragma once
#include <cstdint>
#include <cmath>
namespace sots::sim {
// Truncating float -> int32 conversion. Out-of-range input saturates (the original
// helper's behaviour there is undefined; saturating keeps our tests deterministic).
inline int Ftol(double v) {
if (!(v == v)) return 0; // NaN
if (v >= 2147483647.0) return 2147483647;
if (v <= -2147483648.0) return -2147483647 - 1;
return static_cast<int>(v); // C++ static_cast truncates toward zero
}
// Truncating float -> int64 conversion.
inline std::int64_t Ftoi64(double v) {
if (!(v == v)) return 0;
if (v >= 9223372036854775807.0) return INT64_MAX;
if (v <= -9223372036854775808.0) return INT64_MIN;
return static_cast<std::int64_t>(v);
}
// Round-half-away-from-zero to int (used for the per-system output split).
inline int RoundToInt(double v) { return Ftol(std::round(v)); }
inline double Clamp01(double v) { return v < 0 ? 0 : (v > 1 ? 1 : v); }
template <class T>
inline T ClampT(T v, T lo, T hi) { return v < lo ? lo : (v > hi ? hi : v); }
// Saturating add clamped to +/-2,000,000,000 -- the treasury never overflows.
// CONFIDENCE: high.
inline int SaturatingAdd(int a, int b) {
const std::int64_t s = static_cast<std::int64_t>(a) + static_cast<std::int64_t>(b);
constexpr std::int64_t kLimit = 2000000000;
if (s > kLimit) return static_cast<int>(kLimit);
if (s < -kLimit) return static_cast<int>(-kLimit);
return static_cast<int>(s);
}
} // namespace sots::sim