typedef struct named_number_tag {
    const char* name;
    uint64_t number;
} named_number;

const named_number named_numbers[] = {
    { , 100 },
    { , 1000 },
    { , 1000000 },
    { , 1000000000 },
    { , 1000000000000 },
    { , 1000000000000000ULL },
    { , 1000000000000000000ULL }
};

const named_number* get_named_number(uint64_t n) {
    const size_t names_len = sizeof(named_numbers)/sizeof(named_number);
    for (size_t i = 0; i + 1 < names_len; ++i) {
        if (n < named_numbers[i + 1].number)
            return &named_numbers[i];
    }
    return &named_numbers[names_len - 1];
}

size_t append_number_name(GString* str, uint64_t n) {
    static const char* small[] = {
        , , , , , , , , ,
        , , , , , , ,
        , , , 
    };
    static const char* tens[] = {
        , , , , , , , 
    };
    size_t len = str->len;
    if (n < 20) {
        g_string_append(str, small[n]);
    }
    else if (n < 100) {
        g_string_append(str, tens[n/10 - 2]);
        if (n % 10 != 0) {
            g_string_append_c(str, '-');
            g_string_append(str, small[n % 10]);
        }
    } else {
        const named_number* num = get_named_number(n);
        uint64_t p = num->number;
        append_number_name(str, n/p);
        g_string_append_c(str, ' ');
        g_string_append(str, num->name);
        if (n % p != 0) {
            g_string_append_c(str, ' ');
            append_number_name(str, n % p);
        }
    }
    return str->len - len;
}

GString* magic(uint64_t n) {
    GString* str = g_string_new(NULL);
    for (unsigned int i = 0; ; ++i) {
        size_t count = append_number_name(str, n);
        if (i == 0)
            str->str[0] = g_ascii_toupper(str->str[0]);
        if (n == 4) {
            g_string_append(str, );
            break;
        }
        g_string_append(str, );
        append_number_name(str, count);
        g_string_append(str, );
        n = count;
    }
    return str;
}

void test_magic(uint64_t n) {
    GString* str = magic(n);
    printf(, str->str);
    g_string_free(str, TRUE);
}

int main() {
    test_magic(5);
    test_magic(13);
    test_magic(78);
    test_magic(797);
    test_magic(2739);
    test_magic(4000);
    test_magic(7893);
    test_magic(93497412);
    test_magic(2673497412U);
    test_magic(10344658531277200972ULL);
    return 0;
}