In my previous answer I showed how I did print 128bit numbers based on "printf()".
I have implemented a 256bit unsigned integer type uint256_t as:
typedef __uint128_t uint256_t[2];
I have implemented the operations needed, some like "sqr()" taking an __uint128_t as argument and computing uint256_t as result.
I had hexadecimal print for uint256_t, and now wanted decimal print. But currently my uint256_t has only "mod_256()", but no "div()", so "n/=10" seen in many answers was no option. I found a (slow) solution that works, and since I use prints outside timed secions only, this is acceptable. Code can be found in this gist (including compile command details):
https://gist.github.com/Hermann-SW/83c8ab9e10a0bb64d770af543ed08445
In case you run sqr.cpp with an arg, it just outputs UINT256_MAX and exits:
if (argc>1) { pu256(UINT256_MAX); puts(""); return 0; }
$ ./sqr 1
115792089237316195423570985008687907853269984665640564039457584007913129639935
$
The tricky part was the recursive call to go up to maximal used digit, and subtract 1st digit and output that. Recursion does the rest. Function "pu256()" used fast multiplication by 10 "mul10()":
...
void mul10(uint256_t d, uint256_t x)
{
uint256_t t = { x[0], x[1] };
shl_256(t, 2);
add_256(d, x, t);
shl_256(d, 1);
}
const uint256_t UINT256_MAX_10th = UINT256( UINT128(0x1999999999999999, 0x9999999999999999), UINT128(0x9999999999999999, 0x999999999999999A) );
void pu256_(uint256_t v, uint256_t t, const uint256_t o)
{
if (!lt_256(v, t) && le_256(o, UINT256_MAX_10th))
{
uint256_t nt, no = { t[0], t[1] };
mul10(nt, t);
pu256_(v, nt, no);
}
char d = '0';
while (le_256(o, v))
{
sub_256(v, v, o);
++d;
}
putchar(d);
}
void pu256(const uint256_t u)
{
if ((u[1]==0) && (u[0]==0)) putchar('0');
else
{
uint256_t v = { u[0], u[1] }, t = UINT256( 0, 10 ), o = UINT256( 0, 1 );
pu256_(v, t, o);
}
}
...
As said, this approach only makes sense for integer type missing division operation.