Algorithmus zum Umwandeln der unendlich langen Basis 2^32 Nummer in druckbare Basis 10

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

  •  05-07-2019
  •  | 
  •  

Frage

Ich repräsentiere eine unendlich präzise ganze Zahl als eine Reihe unsignierter INTs für die Verarbeitung an einer GPU. Für Debugging -Zwecke möchte ich die Basis 10 -Darstellung einer dieser Zahlen drucken, habe aber Schwierigkeiten, meinen Kopf um sie herum zu wickeln. Hier ist, was ich gerne tun würde:

//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);

Irgendwelche Vorschläge, wie man dieses Problem angeht?

Bearbeiten: Hier ist eine vollständige Implementierung dank 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);
}
War es hilfreich?

Lösung

Wenn Sie Zugriff auf 64 -Bit -Arithmetik haben, ist dies einfacher. Ich würde etwas in der Reihe von:

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 () und reverse () links zum Implementieren. Divideby10 teilt sich um 10 und kehrt den Rest zurück.

Andere Tipps

Grundsätzlich benötigen Sie einen klassischen Dezimaldruck mit der Ziffernproduktion, indem Sie Ihre Nummer wiederholt durch zehn (in Ihrer Basis 2^32) und den Rest als Ziffern verwenden. Möglicherweise haben Sie keine Kluft durch (irgendetwas, geschweige denn) 10 Routine, was wahrscheinlich die Schlüsselquelle Ihres Problems ist.

Wenn Sie in C oder C ++ arbeiten, erhalten Sie ein vollständiges unendliches Präzisions -Arithmetikpaket von GNU Bignum -Paket. Die meisten anderen weit verbreiteten Sprachen haben ähnliche Pakete.

Wenn Sie zu viel Freizeit haben, können Sie natürlich jederzeit selbst eine Multipulecision -Division implementieren. Sie leihen sich bereits eine Terminologie von Knuth. Er liefert auch die Multipkrezisionsalgorithmen in seminumerischen Algorithmen.

Wenn es .NET ist, schauen Sie sich an Diese Implementierung einer BiginTeger -Klasse.

Wie wäre es mit langen Doppel? Dann erhalten Sie 80bit in der Mantissa, aber ich denke, dass die Genauigkeit bei der Verwendung schwimmender Punktzahlen verloren geht.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top