[Math] the most mathematically sound way to define the “damage per second” for a weapon

arithmeticrecreational-mathematics

Consider a weapon firing shots every $f^{-1}$ seconds (i.e. $f$ is the weapon's fire rate). Each shot deals $n$ damage to is target. Consider another weapon firing every $3f^{-1}$ second, but dealing $5n$ in damage. You want to determine which weapon has the greatest damage potential, assuming those weapons are equally easy to hit with.

Perhaps the most obvious approach is to divide the damage dealt by the time needed to deal it. Ignoring bullet travel speeds, that'll be $fn$ for the former gun and $\frac53fn$ for the latter. This suggests that the second gun, while perhaps harder to use or less forgiving for mistakes, should be preferred thanks to its superior damage output potential.

Things however become less clear when you throw a few variables in the mix:

  • You usually can only arm so many shots in your weapon at any one time (magazine size)
  • You can only reload a weapon so fast (reload time)
  • Some weapons take more time to reload the first piece of ammunition than the subsequent ones
  • You can only carry so many shots for one weapon before running out (ammo capacity)
  • Some weapons can do fancy things such as having a chance to set the target on fire
  • Some weapons have a (non-fixed) chance of dealing random critical hits that deal more damage than usual, some weapons have guaranteed ways to achieve that (headshots), some weapons or combinations thereof ("builds") have a mixture of both
  • Some weapons are more accurate than others (accuracy and recoil)
  • Some weapons may be more effective against certain enemies than others (damage type and resistances in Borderlands 2)

…et ceatera. I find that, rather than attempting to come up with an explicit DPS formula, it's both more simple and more flexible to simply simulate the gun's firing for a while and then divide the damage dealt by the simulation time. In pseudo code:

def dps(gun):
  gun.load()
  time = 0
  damage = 0
  while simulation is not over: #???
    damage += gun.fire()
    time += 1/gun.fire_rate
    if gun.magazine_empty():
      gun.reload()
      time += gun.reload_time
  return damage/time

My conundrum however is determining an appropriate condition to stop the simulation in order to avoid introducing distortions around the cutoff point.

Consider for example a simulation end condition such as "stop after 15 seconds because you probably aren't going to keep firing a gun to a target for longer than that." If a gun does a full empty-magazine-reload-magazine cycle in 3 or 5 seconds, that's probably okay. If a gun empties its magazine in 14 seconds and reloads in 2, the current pseudo code will also do the right thing and divide the damage output by 16 seconds. If, however, the cutoff point happens while the gun is unloading, that might introduce distortions that make the DPS number less useful in its ultimate purpose as a (partial) ordering criterion over the set of weapons.

What should then be my frame of reference?

  • One full fire-reload cycle? (Might save on computations.)
  • Firing the weapon until I run out of ammo? (Handles the situation where your ammo carried isn't a multiple of your magazine size, which is a problem against sufficiently healthy foes)
  • Firing the weapon until I hit a given amount of damage? (Think a situation where all your opponents can take the same amount of damage before they are disabled.)
  • Firing the weapon for a fixed amount of seconds anyway?

Best Answer

One commonly useful method is to measure one cycle -- find two points in time where the conditions at the beginning time and the end time are the same. Then compute DPS as being the amount of damage done between those two points in time divided by the duration between those points in time.

e.g. if there is only "open fire" and "time to reload", you could take one cycle to consist of firing until the magazine is empty then reloading. So the starting point is when you start firing, and the ending point is when you begin firing again after reloading.

For probabilistic things (e.g. a weapon has a 10% chance to do a 'critical hit' of double damage), you can replace the actual damage done with the average damage done. If you have a weapon that does 10 damage 90% of the time and 20 damage 10% of the time, just assume it does 11 (i.e. $10 \cdot 0.9 + 20 \cdot 0.1$) damage all of the time.


Do keep in mind downtime needs to be accounted for. If you need to do 100 damage to kill an enemy then have a lull before you move on to the next enemy, then of the two weapons:

  • One clip does 100 damage in 1 second, but has a 3 second reload time (50 DPS)
  • One clip does 200 damage over 3 seconds, but has a 1 second reload time (100 DPS)

then the first weapon may easily turn out to be superior, because it does 100 DPS in the time frame that actually matters, whereas the second weapon only does 66 DPS.

Accounting for this can be trickier, but unfortunately it is usually very relevant in the problems where DPS is an important statistic.


Another important factor is overkill. If you are attacking units with 35 HP, then a weapon that fires one shot every second that does 6 damage is better than a weapon that fires one shot every 8 seconds that does 75 damage.

Related Question