Home » What data-type should I use for in-game currency?

What data-type should I use for in-game currency?

Solutons:


You can use int, and consider everything in cents. $1.20 is just 120 cents. At display, you put the decimal in where it belongs.

Interest calculations would just be either truncated or rounded up. So

newAmt = round( 120 cents * 1.04 ) = round( 124.8 ) = 125 cents

This way you don’t have messy decimals always sticking around. You could get rich by adding the unaccounted for money (due to round-downs) into your own bank account

Okay, I’ll jump in.

My advice: it’s a game. Take it easy and use double.

Here is my rationale:

  • float does have a precision issue that appears when adding units to millions, so though it might be benign, I would avoid that type. double only starts getting problems around the quintillons (a billion billions).
  • Since you are going to have interest rates, you will need theoretical infinite precision anyway: with 4% interest rates, $100 will become $104, then $108.16, then $112.4864, etc. This makes int and long useless because you don’t know where to stop with the decimals.
  • BigDecimal will give you arbitrary precision but will become painfully slow, unless you clamp the precision at some time. What are the rounding rules? How do you choose where to stop? Is it worth having more precision bits than double? I believe not.

The reason fixed point arithmetic is used in financial applications is because they are deterministic. The rounding rules are perfectly defined, sometimes by the law, and must be strictly applied, but rounding still happens at some point. Any argument in favour of a given type based on precision is likely bogus. All types have precision issues with the kind of computations you are going to do.

Practical examples

I see quite a few comments claiming things about rounding or precision that I disagree with. Here are a few additional examples to illustrate what I mean.

Storing: if your base unit is the cent, you’ll probably want to round to the nearest cent when storing values:

void SetValue(double v) { m_value = round(v * 100.0) / 100.0; }

You will get absolutely no rounding problems when adopting this method that you wouldn’t also have with an integer type.

Retrieving: all computations can be done directly on the double values, with no conversions:

double value = data.GetValue();
value = value / 3.0 * 12.0;
[...]
data.SetValue(value);

Note that the above code does not work if you replace double with int64_t: there will be an implicit conversion to double, then truncation to int64_t, with a possible loss of information.data.GetValue()

Comparing: comparisons are the one thing to get right with floating-point types. I suggest using a comparison method such as this one:

/* Are values equal to a tenth of a cent? */
bool AreCurrencyValuesEqual(double a, double b) { return abs(a - b) < 0.001; }

Rounding fairness

Suppose you have $9.99 in the account with 4% interest. How much should the player earn?With integer rounding you get $0.03; with floating-point rounding you get $0.04. I believe the latter is more fair.

Floating point types in Java (float, double) are not good representation for currencies because of one main reason – there is a machine error in rounding. Even if a simple calculation returns a whole number – like 12.0/2 (6.0), the floating point might wrongly round it (due tho the specific representation of these types in memory) as 6.0000000000001 or 5.999999999999998 or similar. This is a result of the specific machine rounding that occurs in the processor and it is unique to the computer that calculated it. Usually, it is rarely an issue to operate with these values, since the error is quite negligent, but its a pain to display that to the user.

A possible solution to this would be to use a custom implementations of floating point data type, like BigDecimal. It supports better calculation mechanisms which at least isolate the rounding errors not to be machine specific, but are slower in terms of performance.

If you need high productivity, you’d better stick to the simple types. In case you operate with important financial data, and each cent is important (like a Forex application, or some casino game) then I’d recommend you to use Long or long. Long would allow you to handle large amounts and good precision. Just assume you need, lets say, 4 digits after the decimal point, all you need is to multiply the amount by 10000. Having experience in developing on-line casino games, I’ve seen Long to be often used to represent the money in cents. In Forex applications, the precision is more important, so you’ll need a greater multiplier – still, whole numbers are free of machine rounding issues (of course manual rounding like in 3/2 you should handle yourself).

An acceptable option would be to use the standard floating point types – Float and Double, if performance is more important than accuracy to hundredths of the cent. Then, on your display logic, all you need is to use a predefined formatting, so that the ugliness of potential machine rounding does not get to the user.

Related Solutions

Extract file from docker image?

You can extract files from an image with the following commands: docker create $image # returns container ID docker cp $container_id:$source_path $destination_path docker rm $container_id According to the docker create documentation, this doesn't run the...

Transfer files using scp: permission denied

Your commands are trying to put the new Document to the root (/) of your machine. What you want to do is to transfer them to your home directory (since you have no permissions to write to /). If path to your home is something like /home/erez try the following:...

What’s the purpose of DH Parameters?

What exactly is the purpose of these DH Parameters? These parameters define how OpenSSL performs the Diffie-Hellman (DH) key-exchange. As you stated correctly they include a field prime p and a generator g. The purpose of the availability to customize these...

How to rsync multiple source folders

You can pass multiple source arguments. rsync -a /etc/fstab /home/user/download bkp This creates bkp/fstab and bkp/download, like the separate commands you gave. It may be desirable to preserve the source structure instead. To do this, use / as the source and...

Benefits of Structured Logging vs basic logging

There are two fundamental advances with the structured approach that can't be emulated using text logs without (sometimes extreme levels of) additional effort. Event Types When you write two events with log4net like: log.Debug("Disk quota {0} exceeded by user...

Interfaces vs Types in TypeScript

2019 Update The current answers and the official documentation are outdated. And for those new to TypeScript, the terminology used isn't clear without examples. Below is a list of up-to-date differences. 1. Objects / Functions Both can be used to describe the...

Get total as you type with added column (append) using jQuery

One issue if that the newly-added column id's are missing the id number. If you look at the id, it only shows "price-", when it should probably be "price-2-1", since the original ones are "price-1", and the original ones should probably be something like...

Determining if a file is a hard link or symbolic link?

Jim's answer explains how to test for a symlink: by using test's -L test. But testing for a "hard link" is, well, strictly speaking not what you want. Hard links work because of how Unix handles files: each file is represented by a single inode. Then a single...

How to restrict a Google search to results of a specific language?

You can do that using the advanced search options: http://www.googleguide.com/sharpening_queries.html I also found this, which might work for you: http://www.searchenginejournal.com/how-to-see-google-search-results-for-other-locations/25203/ Just wanted to add...

Random map generation

Among the many other related questions on the site, there's an often linked article for map generation: Polygonal Map Generation for Games you can glean some good strategies from that article, but it can't really be used as is. While not a tutorial, there's an...

How to prettyprint a JSON file?

The json module already implements some basic pretty printing in the dump and dumps functions, with the indent parameter that specifies how many spaces to indent by: >>> import json >>> >>> your_json = '["foo", {"bar":["baz", null,...

How can I avoid the battery charging when connected via USB?

I have an Android 4.0.3 phone without root access so can't test any of this but let me point you to /sys/class/power_supply/battery/ which gives some info/control over charging issues. In particular there is charging_enabled which gives the current state (0 not...

How to transform given dataset in python? [closed]

From your expected result, it appears that each "group" is based on contiguous id values. For this, you can use the compare-cumsum-groupby pattern, and then use agg to get the min and max values. # Sample data. df = pd.DataFrame( {'id': [1, 2, 2, 2, 2, 2, 1, 1,...

Output of the following C++ Program [closed]

It works exactly like this non-recursive translation: int func_0() { return 2; } int func_1() { return 3; } int func_2() { return func_1() + func_0(); } // Returns 3 + 2 = 5 int func_3() { return func_2() + func_1(); } // Returns 5 + 3 = 8 int func_4() { return...

Making a circle out of . (periods) [closed]

Here's the maths and even an example program in C: http://pixwiki.bafsoft.com/mags/5/articles/circle/sincos.htm (link no longer exists). And position: absolute, left and top will let you draw: http://www.w3.org/TR/CSS2/visuren.html#choose-position Any further...

Should I use a code converter (Python to C++)?

Generally it's an awful way to write code, and does not guarantee that it will be any faster. Things which are simple and fast in one language can be complex and slow in another. You're better off either learning how to write fast Python code or learning C++...

tkinter: cannot concatenate ‘str’ and ‘float’ objects

This one line is more than enough to cause the problem: text="რეგულარი >> "+2.23+ 'GEL' 2.23 is a floating-point value; 'GEL' is a string. What does it mean to add an arithmetic value and a string of letters? If you want the string label 'რეგულარი...