Add to Technorati Favorites
February 2012
S M T W T F S
« Nov    
 1234
567891011
12131415161718
19202122232425
26272829  

Entrecard Drop List

Join our Entrecard Drop List

The occasional annoyance of integer math.

Readers are always asking me to share some actual insight into the game development process. I always worry that it might be boring for people. I’ll give it a shot though:

Integers are great. For those of you not familiar with integers, they are basically positive or negative whole numbers: 1, 2, 3, -1, -2, -3, etc. Integers do not have decimal places. In programming, you tend to use integers more than any other kind of number because computers handle them best. Decimals (or floating point numbers) require more memory to store and more processing power to work with.

But integers are not always great. For example, take the market (auction house) I have been working on for Primordiax. Assume a base listing fee of 5% of the value of the item being sold. Now assume you are selling the item for 10 triads. 5% is less than 1 unit. So how do you deduct less than 1 of something from someone? You can’t. So I have to round up to make it work, which means the listing fee is 1. (Just so you know, in computer integer math, remainders are always rounded down. Thus, 4.9 becomes 4.) So while it was supposed to be 5%, it is now effectively 10%.

Another example. Assume you have damage resistance of 20%. You are hit for 12 pts of damage. You don’t avoid 2.4 damage, you only avoid 2 damage. So instead of 20%, you only got 16% damage resistance. For this amount of damage, your resistance could go as high as 23% and you would still only resist 2 points. So in the end, for this amount of damage, 16-23% damage resistance are effectively the same. :(

What is the solution? Usually the solution is to just work with bigger numbers. When I was confronted with the above problems, this is how I solved it:

1) I changed the triad currency to be 100 times larger. It is a bank/economic currency only, so players convert other currencies they actually find in game to triads. The base conversion rate of those currencies was 1:1 (1 danar, drocta, or sathu = 1 triad). Eventually the economy and currencies will float with demand, but that is another issue. I changed it from 1:1 to 1:100. So 1 danar, drocta, or sathu will now convert into 100 triad.

This still means someone could potentially sell something for 5 triad and get hit with the same problem, but it is less likely since 5 triad is kinda like 5 cents in a world where people rarely buy things for less than at least a dollar.

2) I multiplied all player and mob hp by 10, and also all DPS and damage formulas by 10. Fortunately, I centralized by DPS and damage formulas in a single daemon early on (so I could easily make changes to how damage formulas worked) so this was not super difficult.

You could argue I cheated, I guess. The same problem still lurks in the depths of the game’s formulas, but at least now the effect is much smaller and thus far less noticeable.

Anyway, these are the types of issues that may seem pretty trivial but actually end up taking significant developer thought and effort when working on games.

16 comments to The occasional annoyance of integer math.

  • Longasc

    I can only say: Kudos for maintaining your personal integrity. Don’t fall for the dark side, the floating point.

  • HB

    For all the trouble integer math can be, floating point math can turn out to be a much stranger beast. You’ve done the right thing by keeping integers and adding precision (more “decimal points”). You can add another half point of precision at the cost of doing some more math.

    For X/Y
    If you want to “round up” in integer math (5/2 = 2.5 -> 3 instead of 2)
    result = (X + Y/2) / Y
    If you want to know the ceiling (You auction house example or how many buckets does it take to hold 11 apples if each bucket holds 10 apples ~ answer = 11)
    result = (X + Y – 1) / Y

    Also remember these errors compound the more operations you do. There is a whole branch of mathematics called numerical methods to come up with ways to reduce these errors as computations become more complex.

  • HB, great tips there, and I use some of those exact formulas sometimes. I will have to look into that branch of mathematics.

    One thing I regret from my college years is that I took absolutely zero math or science classes. I majored in international law, organization, and politics (a Georgetown University major in their School of Foreign Service) so we didn’t have to take any. I missed out on a great chance to learn advanced mathematics.

    What really hurt me is the fact that growing up in Georgia and South Carolina, math in particular seemed to be a pathetically ignored topic. I’d say 3/4 of my math teachers were coaches who they dumped into teaching math just to satisfy sports rules (you can’t have coaches who just coach – they have to teach). As a result, math class was usually miserable. I usually had to teach myself, and eventually that gets old to a teenager.

    If I’d know then how awesome math is, and that it is truly what defines the universe, I would have been more involved in it.

  • I don’t really see it as cheating, just using what actually works best for you. The good part is that if you need to convert those larger solutions into floats for data beyond your control, say screen coordinates for instance, you can just divide them by the correct power of 10.

    My personal theory is that if you aren’t an engine programmer, you don’t really need to disappear into math textbooks. If you run into any really bad problems, just cheat. =P

  • Hehehehe Sara. That’s my attitude. A little cheating, as long as it isn’t inefficient or a kludge, doesn’t hurt anyone. Sometimes I feel kinda guilty, but I think I am just being too hard on myself.

  • Talsek

    Good article. I like finding out how different developers think and approach problems. I can also relate to the late-blooming interest in math :) . It’s like the academic version of taking apart your toys to see what’s inside.

  • Meridian 59’s scripting system uses integer math, too. There’s a bunch of tricks you learn while doing that. For example, do multiplications before divisions to keep rounding from throwing off the values in a complex equation. Knowing how to factor equations was useful.

    Integer math also made it easier to store multiple values in less space. M59’s spells/skills are stored as a single number: the first part is the spell/skill ID, and the last two digits were your proficiency. That meant that the whole value could be stored in one integer. value / 100 = skill/spell ID. value modulo 100 = proficiency.

  • That last example is brilliant, Brian. I occasionally have a good idea like that where I use a math “trick” (they seem like tricks to me at least) to use numbers to store data in a complicated way.

    Reading your example, and thinking of a few of my own, just amplifies my lament for such poor math education in high school. What a loss. :(

  • Xenovore

    In this day and age, limiting yourself to only integer math is rather like poking your eyes out because the sun is too bright — it’s a solution, but hardly the best solution.

    Use floating point where it makes sense, I say (like in your examples above). With modern processors, the performance gain of integers over floats is minimal. And floating point is unavoidable anyway if you’re doing any 3D graphics…

    But, if you feel you must stick primarily with integers, you could use fixed-point math

  • Fixed point math would be nice as well.

    But in game terms, sometimes you are still left with a “what do I do now” when you need to deduct .4 of a hit point from someone, or charge someone .6 of a unit of currency.

  • Xenovore

    Well, that’s what I was alluding to… It makes sense to use floating point for those, rounding as necessary. It depends on what you want to do with them as well.

    In other words, for 0.4 HP, do you want to give the player the benefit and round down to 0, or always round up, so it’s at least 1 HP? Personally, I think rounding to the nearest whole amount works fine for hit points.

    In the case of currency, I imagine you’d want to always round up — that’s essentially what we do with real world currency, e.g. if the smallest denomination were 5 cents, it’s rather unlikely that something would cost $2.16; it would actually be bumped up to $2.20.

  • Xenovore

    After re-reading the original post, I thought of something else with regard to damage output/input that might be helpful.

    I don’t know how your combat is segmented, i.e. is it turn-based or real-time? But either way, the combat can be segmented into periods, “sub-rounds” or “ticks”, to minimize the rounding error — during each tick, damage is accumulated but not applied until the end of the tick.

    So, for example, let’s say the combat tick is 1 second long; and during that period 3 attacks are made, mitigated by the 20% damage resistance:

    1) 12 HP * 0.20 = 2.4 HP.
    2) 18 HP * 0.20 = 3.6 HP.
    3) 9 HP * 0.20 = 1.8 HP.

    Total damage is 7.8 HP at the end of the tick. Then it’s rounded and applied for 8 HP. Another benefit is that the damage resistance only needs to apply once, i.e. 12 + 18 + 9 = 39 * 0.20 = 7.8.

  • BryanM

    Floating point variables are the bane of my existence.

    A problem is the bigger a number gets, the less precise they become. This is obvious when you think about it – it’s essentially a binary version of scientific notation, crammed into a few bits like an entire ham into a small can.

    So when you want to subtract, say, .6345 from something… it decides to go nuts and in reality subtract .64, or something even more perverse than that.

    In a platformer thing I’m making, I started off using floats, in my childish naive innocence. The glitchiness became apparent once I started generating screens – seems would appear, inevitably, between tiles where the rounding on floats got funky.

    I tried some funky approaches to solving this – having tiles overlap one another very slightly (like .01 of a pixel) etc, but the solution was very simple: don’t use floats, use fixed point numbers instead.

    The largest data types can store something like the distance to Pluto in meters or something – so what is the benefit of floaty point in this situation?

    And in what situations are floating point variables the best tool for the job? In a nuclear bomb simulator, for example, I can’t imagine they wouldn’t want very precise values instead of whatever arbitrary values the IEEE Standard permits…

  • Xeno and Bryan: I don’t have much to add other than to thank you for posting. Great insights into how work around float/int issues. :)

  • grande tosimpe de icoibamot y entra con brado cetopria. argues a mimondu y glicadeto treras con blembuvo engrapalo!

  • We’re a gaggle of volunteers and opening a new scheme in our community. Your site provided us with useful info to paintings on. You’ve performed a formidable process and our entire neighborhood shall be grateful to you.

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>