1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-22 22:13:35 +02:00

Merge pull request #4358 from IvanSavenko/integer_divide

Add helper functions for integer division rounding
This commit is contained in:
Ivan Savenko 2024-08-06 18:10:03 +03:00 committed by GitHub
commit a4dd510735
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 33 additions and 5 deletions

View File

@ -706,6 +706,33 @@ namespace vstd
return a + (b - a) * f; return a + (b - a) * f;
} }
/// Divides dividend by divisor and rounds result up
/// For use with integer-only arithmetic
template<typename Integer1, typename Integer2>
Integer1 divideAndCeil(const Integer1 & dividend, const Integer2 & divisor)
{
static_assert(std::is_integral_v<Integer1> && std::is_integral_v<Integer2>, "This function should only be used with integral types");
return (dividend + divisor - 1) / divisor;
}
/// Divides dividend by divisor and rounds result to nearest
/// For use with integer-only arithmetic
template<typename Integer1, typename Integer2>
Integer1 divideAndRound(const Integer1 & dividend, const Integer2 & divisor)
{
static_assert(std::is_integral_v<Integer1> && std::is_integral_v<Integer2>, "This function should only be used with integral types");
return (dividend + divisor / 2 - 1) / divisor;
}
/// Divides dividend by divisor and rounds result down
/// For use with integer-only arithmetic
template<typename Integer1, typename Integer2>
Integer1 divideAndFloor(const Integer1 & dividend, const Integer2 & divisor)
{
static_assert(std::is_integral_v<Integer1> && std::is_integral_v<Integer2>, "This function should only be used with integral types");
return dividend / divisor;
}
template<typename Floating> template<typename Floating>
bool isAlmostZero(const Floating & value) bool isAlmostZero(const Floating & value)
{ {

View File

@ -145,7 +145,8 @@ int DamageCalculator::getActorAttackIgnored() const
if(multAttackReductionPercent > 0) if(multAttackReductionPercent > 0)
{ {
int reduction = (getActorAttackBase() * multAttackReductionPercent + 49) / 100; //using ints so 1.5 for 5 attack is rounded down as in HotA / h3assist etc. (keep in mind h3assist 1.2 shows wrong value for 15 attack points and unupg. nix) //using ints so 1.5 for 5 attack is rounded down as in HotA / h3assist etc. (keep in mind h3assist 1.2 shows wrong value for 15 attack points and unupg. nix)
int reduction = vstd::divideAndRound( getActorAttackBase() * multAttackReductionPercent, 100);
return -std::min(reduction, getActorAttackBase()); return -std::min(reduction, getActorAttackBase());
} }
return 0; return 0;

View File

@ -227,7 +227,7 @@ TResources CGTownInstance::dailyIncome() const
auto playerSettings = cb->gameState()->scenarioOps->getIthPlayersSettings(getOwner()); auto playerSettings = cb->gameState()->scenarioOps->getIthPlayersSettings(getOwner());
for(TResources::nziterator it(ret); it.valid(); it++) for(TResources::nziterator it(ret); it.valid(); it++)
// always round up income - we don't want to always produce zero if handicap in use // always round up income - we don't want to always produce zero if handicap in use
ret[it->resType] = (ret[it->resType] * playerSettings.handicap.percentIncome + 99) / 100; ret[it->resType] = vstd::divideAndCeil(ret[it->resType] * playerSettings.handicap.percentIncome, 100);
return ret; return ret;
} }
@ -1271,7 +1271,7 @@ int GrowthInfo::totalGrowth() const
ret += entry.count; ret += entry.count;
// always round up income - we don't want buildings to always produce zero if handicap in use // always round up income - we don't want buildings to always produce zero if handicap in use
return (ret * handicapPercentage + 99) / 100; return vstd::divideAndCeil(ret * handicapPercentage, 100);
} }
void CGTownInstance::fillUpgradeInfo(UpgradeInfo & info, const CStackInstance &stack) const void CGTownInstance::fillUpgradeInfo(UpgradeInfo & info, const CStackInstance &stack) const

View File

@ -200,7 +200,7 @@ ui32 CGMine::getProducedQuantity() const
{ {
auto * playerSettings = cb->getPlayerSettings(getOwner()); auto * playerSettings = cb->getPlayerSettings(getOwner());
// always round up income - we don't want mines to always produce zero if handicap in use // always round up income - we don't want mines to always produce zero if handicap in use
return (producedQuantity * playerSettings->handicap.percentIncome + 99) / 100; return vstd::divideAndCeil(producedQuantity * playerSettings->handicap.percentIncome, 100);
} }
void CGMine::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const void CGMine::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const

View File

@ -1267,7 +1267,7 @@ void BattleActionProcessor::handleDeathStare(const CBattleInfoCallback & battle,
vstd::amin(chanceToKill, 1); //cap at 100% vstd::amin(chanceToKill, 1); //cap at 100%
int killedCreatures = gameHandler->getRandomGenerator().nextBinomialInt(attacker->getCount(), chanceToKill); int killedCreatures = gameHandler->getRandomGenerator().nextBinomialInt(attacker->getCount(), chanceToKill);
int maxToKill = (attacker->getCount() * singleCreatureKillChancePercent + 99) / 100; int maxToKill = vstd::divideAndCeil(attacker->getCount() * singleCreatureKillChancePercent, 100);
vstd::amin(killedCreatures, maxToKill); vstd::amin(killedCreatures, maxToKill);
killedCreatures += (attacker->level() * attacker->valOfBonuses(BonusType::DEATH_STARE, BonusCustomSubtype::deathStareCommander)) / defender->level(); killedCreatures += (attacker->level() * attacker->valOfBonuses(BonusType::DEATH_STARE, BonusCustomSubtype::deathStareCommander)) / defender->level();