0xFF...FF / 10 == 0x19...99

A few weeks ago, I wrote a C++ routine to parse decimal numbers using the overflow detection principles of SafeInt. I couldn't find anything in the libraries that actually did a good job of checking for overflow.

Briefly, to see if unsigned values A+B overflow, check if (A > MAX_UINT - B). Similarly, A*B will overflow if (A > MAX_UINT / B).

// Convert a string to an unsigned. Returns 'true' iff conversion is legitimate. bool StringToUnsigned( const string& str,
unsigned& rUint)
{
rUint = 0;

if (str.empty())
return false;

for (unsigned i = 0; i < str.length(); ++i)
{
if (!isdigit(str[i]))
return false;

// Check for numeric overflow. if (rUint > numeric_limits<unsigned>::max() / 10)
return false;
rUint *= 10;

unsigned d = str[i] - '0';
if (rUint > numeric_limits<unsigned>::max() - d)
return false;
rUint += d;
}

return true;
}

While debugging this code, I noticed something interesting. 0xFFFFFFFF divided by ten (0xA) is 0x19999999. This pattern holds for smaller and larger sequences of 0xFF...FF too: 0xFF/10 = 0x19; 0xFFFF/10 = 0x1999; and so on.

I'm not sure how to prove this, but I can prove the closely related result: 0x19...99 * 10 = 0xFF...FA:

 10 * N         = 8 * N  +  2 * N
10 * 0x19...99 = 8 * 0x19...99 + 2 * 0x19...99

0x199...99 = %0001 1001 1001 ... 1001 1001

10 * 0x19...99 = %1100 1100 1100 ... 1100 1000
+ %0011 0011 0011 ... 0011 0010
= %1111 1111 1111 ... 1111 1010

A mildly curious result of no value, but it amused me.

5 Comments

  • You can prove it by binary arithmetic. Start with the simplest case, 15/10 or 0xF/0xA. This results in binary 1.1000 or 1.8 hex. Now, do you notice a pattern? Now try 0xFF/0x0A. In decimal, this will be 25.5. In binary, this will be 1_1001.1000. If we truncate this, 255/10 = 25 or in hex 0xFF/0x0A = 19. Remember that the exact result is 19.8 hex! Notice that 0x19 will be the most signficant word whenever you have 2^8-1, 2^16-1, etc as the dividend.



    Now for 65535/10 we get 6553.5. In binary, this is 0001_1001_1001_1001.1000. From this, we can see that shifting this result once to the left (equivalent to multiplication by 2) we get 0011_0011_0011_0011.0000 and left shifting the original result by 3 (equivalent to multiplication by 8) gives 1100_1100_1100_1100.0000. Summed, we get 1100_1100_1100_1100.0000 + 0011_0011_0011_0011.0000 = 1111_1111_1111_1111.0000 or, 0xFFFF. QED :)

  • pIU2ns Im grateful for the article.Thanks Again. Cool.

  • CmbdzH Looking forward to reading more. Great article.Much thanks again. Really Cool.

  • Enjoyed every bit of your article post.Really looking forward to read more. Awesome.

  • Greetings! Very useful advice in this particular post! It is the little changes that make the biggest changes. Thanks for sharing!

Comments have been disabled for this content.