Algoritmo para converter infinitamente longa base 2^32 Número em base imprimível 10

StackOverflow https://stackoverflow.com/questions/1809468

  •  05-07-2019
  •  | 
  •  

Pergunta

Estou representando um número inteiro infinitamente preciso como uma variedade de INTs não assinados para o processamento de uma GPU. Para fins de depuração, gostaria de imprimir a representação da base 10 de um desses números, mas estou tendo dificuldade em envolver minha cabeça. Aqui está o que eu gostaria de fazer:

//the number 4*(2^32)^2+5*(2^32)^1+6*(2^32)^0
unsigned int aNumber[3] = {4,5,6};
char base10TextRepresentation[50];
convertBase2To32ToBase10Text(aNumber,base10TextRepresentation);

Alguma sugestão sobre como abordar esse problema?

EDIT: Aqui está uma implementação completa graças a Drhirsch

#include <string.h>
#include <stdio.h>
#include <stdint.h>

#define SIZE 4

uint32_t divideBy10(uint32_t * number) {
  uint32_t r = 0;
  uint32_t d;
  for (int i=0; i<SIZE; ++i) {
    d = (number[i] + r*0x100000000) / 10;
    r = (number[i] + r*0x100000000) % 10;
    number[i] = d;
  }
  return r;
}

int zero(uint32_t* number) {
  for (int i=0; i<SIZE; ++i) {
    if (number[i] != 0) {
      return 0;
    }
  }
  return 1;
}

void swap(char *a, char *b) {
  char tmp = *a;
  *a = *b;
  *b = tmp;
}

void reverse(char *str) {
  int x = strlen(str);
  for (int y = 0; y < x/2; y++) {
    swap(&str[y],&str[x-y-1]);
  }
}

void convertTo10Text(uint32_t* number, char* buf) {
  int n = 0;
  do {
    int digit = divideBy10(number);
    buf[n++] = digit + '0';
  } while(!zero(number));
  buf[n] = '\0';
  reverse(buf);
}

int main(int argc, char** argv) {
  uint32_t aNumber[SIZE] = {0,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};
  uint32_t bNumber[4] = {1,0,0,0};

  char base10TextRepresentation[50];

  convertTo10Text(aNumber, base10TextRepresentation);
  printf("%s\n",base10TextRepresentation);
  convertTo10Text(bNumber, base10TextRepresentation);
  printf("%s\n",base10TextRepresentation);
}
Foi útil?

Solução

Se você tem acesso à aritmética de 64 bits, é mais fácil. Eu faria algo na linha de:

int32_t divideBy10(int32_t* number) {
    uint32_t r = 0;
    uint32_t d;
    for (int i=0; i<SIZE; ++i) {
        d = (number[i] + r*0x100000000) / 10;
        r = (number[i] + r*0x100000000) % 10;
        number[i] = d;
        number[i] = r;
}

void convertTo10Text(int32_t* number, char* buf) {
    do {
        digit = divideBy10(number);
        *buf++ = digit + '0';
    } while (!isEqual(number, zero));
    reverse(buf);
}

isequal () e reverse () deixados a serem implementados. Divideby10 divide por 10 e retorna o restante.

Outras dicas

Fundamentalmente, você precisa de impressão decimal clássica usando a produção de dígitos dividindo seu número por dez (na sua base 2^32) repetidamente e usando o restante como dígitos. Você pode não ter uma divisão (qualquer coisa, muito menos) 10 rotina, que provavelmente é a fonte principal do seu problema.

Se você estiver trabalhando em C ou C ++, pode obter um pacote aritmético de precisão infinita completa de Pacote GNU bignum. A maioria dos outros idiomas amplamente utilizados possui pacotes semelhantes disponíveis.

Obviamente, se você tiver muito tempo livre, sempre poderá implementar você mesmo a divisão multiprecision. Você já está emprestando terminologia da Knuth; Ele também fornece os algoritmos de multiprecisão em algoritmos seminuméricos.

Se for .NET, dê uma olhada em Esta implementação de uma classe Biginteger.

Que tal usar duplas longas? Então você obtém 80 bits no Mantissa, mas acho que a precisão está perdida ao usar números de ponto flutuante.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top