wound up going with this:
Code:
#define ACHS_0TO9 "0123456789"
#define ACHS_ATOZ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define ACHS_atoz "abcdefghijklmnopqrstuvwxyz"
typedef struct _ACHN
{
uint not0;
ach sign[2];
ach text[bitsof(umax)];
} ACHN;
typedef struct _ACHF { ACHN full, part, exp; } ACHF;
typedef union _ACHV { ACHF n; ACHN i[3]; } ACHV;
BASIC void umax2achs( ACHN *dst, umax val, achs base )
{
ach tmp[bitsof(umax)] = {0};
uint i = 0, j = 0, max = achsnot0( base );
memset( dst, 0, sizeof(ACHN) );
if ( !max )
return;
while ( val )
{
tmp[j++] = base[val % max];
val /= max;
}
dst->not0 = j;
while ( j )
dst->text[i++] = tmp[--j];
}
BASIC void smax2achs( ACHN *dst, smax val, achs base )
{
if ( val < 0 )
{
umax2achs( dst, -val, base );
dst->sign[0] = '-';
return;
}
umax2achs( dst, val, base );
}
BASIC void ldnum2achs( ACHF *dst, ldnum val, achs base )
{
dint exp = 0;
ldnum full = 0, part = 0;
uint max = achsnot0( base );
if ( !max )
{
memset( dst, 0, sizeof(ACHF) );
return;
}
frexpl( val, &exp );
if ( exp > LDBL_MAX_10_EXP )
{
if ( val < 0 )
{
while ( -val > max )
val /= max;
}
else
{
while ( val > max )
val /= max;
}
}
if ( val > 0u )
{
full = floorl( val );
part = val - full;
}
else
{
full = ceill(val);
part = -(val + full);
}
while ( floorl(part) != part )
part *= max;
smax2achs( &(dst->full), (smax)full, base );
umax2achs( &(dst->part), (umax)part, base );
smax2achs( &(dst->exp), exp, ACHS_0TO9 );
}
Currently untested but I'll get to that later after I fix a pressing bug elsewhere