2017-10-15 4 views
0

J'ai un tableau uint8_t * qui contient un nombre de précision arbitraire bigendien codé.Nombre de précision arbitraire à ascii dans c

J'aimerais obtenir sa représentation Ascii décimale. J'ai donc besoin d'écrire une fonction qui retourne un char *.

L'environnement que j'utilise ne me permet pas d'importer une bibliothèque de précision arbitraire en raison de limitations matérielles. Je suis sûr qu'il y a quelque chose que je peux lire pour l'implémenter facilement. Par exemple, le nombre défini par l'hexagone d53ceb9d32c6ca06 suivant doit être représenté par 15365415089075571206.

+0

Pouvez-vous donner des exemples? Peut-être même un [mcve]? – Yunnosch

+2

Essentiellement, vous devez mettre en œuvre une division longue. –

+0

Cela dépend de la conversion dont vous avez besoin entre le texte et le nombre. Si vous utilisez la racine '100' au lieu de' 256' la sortie du texte est presque triviale, mais il y a un compromis parce que les calculs arithmétiques avec votre bignum devront utiliser le '%' moins efficace au lieu de '&' pour séparer partielle sommes, produits, etc. –

Répondre

-1

Voici une méthode qui devrait fonctionner. Notez qu'il modifie de manière destructive le bigint que vous lui passez, donc si vous vous souciez de la valeur, copiez-le dans un tampon temporaire avant d'appeler la méthode.

En outre, ce n'est pas la version la plus optimisée que vous pourriez écrire, mais si vous demandez comment le faire ici, vous n'êtes probablement pas encore préoccupé par la micro-optimisation avec cela.

#include <stdint.h> 
#include <stdbool.h> 
#include <stdio.h> 
#include <stdlib.h> 

bool is_zero(uint8_t *bigi_data, int bigi_size) { 
    int i = 0; 

    while((i < bigi_size) && (bigi_data[i] == 0)) { 
     i++; 
    } 
    return (i >= bigi_size); 
} 

uint8_t bigdivmod(uint8_t *bigi_data, int bigi_size, uint8_t divisor) { 
    int i = 0; 
    uint16_t ans = 0; 

    while((i < bigi_size) && (bigi_data[i] == 0)) { 
     i++; 
    } 
    for (; i < bigi_size; i++) { 
     ans = ans*256 + bigi_data[i]; 
     bigi_data[i] = ans/divisor; 
     ans = ans % divisor; 
    } 
    return (uint8_t)ans; 
} 

static const char *digits = "abcdefghijklmnopqrstuvwxyz"; 

char *bigitoa(uint8_t *bigi_data, int bigi_size, char *out, int base) { 
    /* Assumes that "out" has enough room. DESTRUCTIVE TO BIGI, so copy */ 
    /* if you care about the value */ 
    /* Only really works for non-negative values */ 
    int i = 0; 
    uint8_t swp; 
    int j; 

    if ((base < 2) || (base > 36)) { 
     return NULL; 
    } 

    if (is_zero(bigi_data, bigi_size)) { 
     out[0] = '0'; 
     out[1] = '\0'; 
     return out; 
    } 

    while (!is_zero(bigi_data, bigi_size)) { 
     out[i++] = digits[bigdivmod(bigi_data, bigi_size, base)]; 
    } 
    out[i] = 0; 
    for (j = 0; j < i/2; j++) { 
     swp = out[i - 1 - j]; 
     out[i - 1 - j] = out[j]; 
     out[j] = swp; 
    } 

    return out; 
} 

int main(int argc, char *argv[]) { 
    uint8_t test_data[] = { 0xd5, 0x3c, 0xeb, 0x9d, 0x32, 0xc6, 0xca, 0x06 }; 
    int test_data_len = sizeof(test_data); 
    char *p; 

    /* Times 3 because we can use three digits to represent 256. If changing */ 
    /* the base below from "10", change this factor. */ 
    p = malloc(3*test_data_len + 1); 

    printf("Test data works out to %s\n", 
      bigitoa(test_data, test_data_len, p, 10)); 

    return 0; 
}