This page is a mirror of Tepples' nesdev forum mirror (URL TBD).

# Fastest method to convert unsigned int to byte array

For my new game, I need a way to convert a two-byte unsigned integer value into an array of byte values where each array item represents one decimal digit.

So, if this is my variable:

static uint number = 24680;

then the converted array (byte numberArray) shall have these values:

numberArray == 2
numberArray == 4
numberArray == 6
numberArray == 8
numberArray == 0

If it's faster and easier to calculate, this would also work:

numberArray == 0
numberArray == 8
numberArray == 6
numberArray == 4
numberArray == 2

Which is the fastest way to do this in Assembly? Is there any established best method for it?
Isn't this just the same old binary to decimal problem that was discussed to death recently and so many times in the past?
If you want to find previous conversations on this topic, this is usually referred to as a conversion to decimal. You might search for "decimal" or for threads about division by 10 / divide by 10 which are almost always the same underlying topic.

The "fastest" way to do this is usually to store the number in decimal form to begin with so you don't have to convert, doing operations on it in decimal as needed.
tokumaru wrote:
Isn't this just the same old binary to decimal problem that was discussed to death recently and so many times in the past?

Well, that's exactly the thing: There are a bazillion threads with several functions per thread.

So, should people who look for an efficient algorithm search through all those threads, trying out each and every attempt manually?

If this topic has been discussed to death, isn't there a final solution? A definite function that does the conversion in the best way possible?

rainwarrior wrote:
The "fastest" way to do this is usually to store the number in decimal form to begin with so you don't have to convert, doing operations on it in decimal as needed.

This might be the fastest way for output. But if you have an energy value that can be decreased by an attack value minus a base defense value minus a temporary status defense value, then is it really the best way to store all these values in five byte long arrays and calculate byte by byte in decimal mode?
DRW wrote:
If this topic has been discussed to death, isn't there a final solution? A definite function that does the conversion in the best way possible?

No. Like with most things there are many ways to approach the problem, and every situation has different needs.

Here's a solution tepples put on the wiki though, along with links to a few others:
http://wiki.nesdev.com/w/index.php/16-bit_BCD

DRW wrote:
This might be the fastest way for output. But if you have an energy value that can be decreased by an attack value minus a base defense value minus a temporary status defense value, then is it really the best way to store all these values in five byte long arrays and calculate byte by byte in decimal mode?

Sometimes yes, sometimes no. It depends on your specific situation. I can't answer that question for you, you're the one that knows how often you're going to need to convert, but here you asked for the fastest converter rather than the fastest attack calculation.
viewtopic.php?f=2&t=11341

The HexToDec999 code by Omegamatrix is the one that fits my needs best.

This one should really be put into the wiki.
(But it should be cleaned up. For some reason, there are a few compiler errors, like when he forgets to add a : after a label name. I'm not sure how such an error could ever happen.)
Not all assemblers require labels to be followed by colons.
rainwarrior wrote:
The "fastest" way to do this is usually to store the number in decimal form to begin with so you don't have to convert, doing operations on it in decimal as needed.

Maybe I just suck at ASM programming, but in my experience this is also a shortcut to terrible hard-to-discover bugs in the way you calculate values. The NES CPU really isn't geared for decimal calculations.

If you only ever add/subtract by one you should be fine though.

But I'd absolutely recommend storing your value in a 16 bit space and using tepples 16-bit BCD every time you need to update your visual output.
I personally prefer to keep numbers that are not used in complex calculations in decimal to begin with. Things like scores, number of coins, and other stuff that only goes through simple addition and subtraction.

Sumez wrote:
The NES CPU really isn't geared for decimal calculations.

Well, it wasn't designed for running SMB3 either, but people made it do that anyway. Doing calculations on decimal digits is exactly the same as working with multi-byte binary numbers, except you have to manually handle the carry and wrapping around. If you write a couple of macros to do it, you don't have to think about this ever again.
Sumez wrote:
But I'd absolutely recommend storing your value in a 16 bit space and using tepples 16-bit BCD every time you need to update your visual output.

tepples' version is slower than the one by Omegamatrix. Especially in situations where your values only need to go to 999. That's the one I'm using now.

Although I had to change it a bit.
For example, he stored the high byte of the integer value in A and the low byte in X.
But passing an integer as a parameter to a function from C, A is the low byte and X the high byte.

Even without C, this is a general inconsistency:

His HexToDec99 and HexToDec255 functions expect their single byte value to be in A.

But HexToDec999 and HexToDec65535 expect the high byte in A and the low byte in X, even though a single byte value is basically the equivalent to the low byte value of an integer, so it's only logical that an integer stored in A and X has the low byte in A and the high byte in X.
Sumez wrote:
rainwarrior wrote:
The "fastest" way to do this is usually to store the number in decimal form to begin with so you don't have to convert, doing operations on it in decimal as needed.

Maybe I just suck at ASM programming, but in my experience this is also a shortcut to terrible hard-to-discover bugs in the way you calculate values. The NES CPU really isn't geared for decimal calculations.

Well, "fast" and "simple" or "safe" are often in opposition. ;P

Though TBH it doesn't really seem much worse than a regular multi-byte add.

For Lizard I wrote some routines for this (1, 2), but I don't think it's a very good example. I didn't need it to be fast, or even simple, it just needed to work, and it did. tokumaru wrote:
Not all assemblers require labels to be followed by colons.

Precisely. My own assembler requires labels to be prefixed with an asterisk (*) for example.

Code:
*main_init
(code)
*main_loop
(code)