C :: Aufgabe #149 :: Lösung #1
1 Lösung
#149
Kaprekar-Konstanten für Hexadezimalzahlen
Fortgeschrittener - C
von hollst
- 27.02.2017 um 19:32 Uhr
Man finde für Zahlen in Hexadezimaldarstellung (Basis 16) alle Kaprekar-Konstanten (sofern vorhanden)
für 3, 4 ... 8stellige Zahlen entsprechend dem Algorithmus aus Aufgabe #165. Die Methode ist
so zu formulieren, dass sie leicht für alle Zahlenbasen von 2 bis 256 verwendbar ist.
für 3, 4 ... 8stellige Zahlen entsprechend dem Algorithmus aus Aufgabe #165. Die Methode ist
so zu formulieren, dass sie leicht für alle Zahlenbasen von 2 bis 256 verwendbar ist.
#1
von devnull (8870 Punkte)
- 08.03.2017 um 09:12 Uhr
Konsolenausgabe:
$ ./hkaprekar
max. 10-stellige Zahl eingeben: ABCh
ABCh
1FEh
DF2h
CF3h
BF4h
AF5h
9F6h
8F7h
7F8h
7F8h
Die Kaprekar-Konstante (9 Iterationen) ist:
7F8h
/********************************************************
* kaprekarb.c Kaprekar-Konstante für allgemeine Basis
********************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAX_BASE_SIZE 256
#define MAX_DIGITS_SIZE 10
#define MAX_ITERATIONS 100
#define DIGIT_DELIMITER '.'
#define BASE_DELIMITER ':'
#define swap(a,b,t) {t=(a);a=(b);b=(t);} /* swap values for sorting */
/* type definition based number */
typedef struct _bnumber {
int base;
int ndigits;
int digits[MAX_DIGITS_SIZE];
} bnumber_t;
enum so_t {ASCENDING, DESCENDING}; /* sorting order */
/* usage */
void print_usage(void) {
printf("%s\n",
"Usage:\n"
" Basis <= 16: ZZZ...Z[bho]\n"
" Z = [0-9a-fA-F]\n"
" b : binär\n"
" h : hexadezimal\n"
" o : oktal\n\n"
" Basis > 16: Z.Z.Z...Z:B\n"
" Z = [0-9]+ mit Z<B\n"
" B = {17..256}\n");
}
/* build based number from string */
int get_bnumber(char *bnstr, bnumber_t *bn) {
char *pb;
int last, n;
size_t wp;
if (bn == NULL || bnstr == NULL || strlen(bnstr)==0)
return -1;
bn->base = 0;
bn->ndigits = 0;
last = strlen(bnstr)-1;
if ((pb = strrchr(bnstr, BASE_DELIMITER)) != NULL) {
if ((bn->base = atoi(pb+1)) > MAX_BASE_SIZE)
return -1;
*pb = 0;
}
else {
last = strlen(bnstr)-1;
if (bnstr[last] == 'h') {
bn->base = 16;
bnstr[last--] = 0;
}
else if (bnstr[last] == 'o') {
bn->base = 8;
bnstr[last--] = 0;
}
else if (bnstr[last] == 'b') {
bn->base = 2;
bnstr[last--] = 0;
}
else if (bnstr[last] >= '0' && bnstr[last] <= '9')
bn->base = 10;
else
return 1;
}
if (bn->base > 16) {
n = 0;
while ((pb = strrchr(bnstr, DIGIT_DELIMITER)) != NULL) {
bn->digits[n++] = atoi(pb+1);
wp = pb-bnstr;
*pb = 0;
}
if (wp > 0)
bn->digits[n++] = atoi(bnstr);
bn->ndigits = n;
}
else {
for (n=last,pb=bnstr; n>=0; n--,pb++) {
if (*pb >= 'a' && *pb <= 'f')
bn->digits[n] = *pb - 'a' + 10;
else if (*pb >= 'A' && *pb <= 'F')
bn->digits[n] = *pb - 'A' + 10;
else if (*pb >= '0' && *pb <= '9')
bn->digits[n] = *pb - '0';
else
return 1;
}
bn->ndigits = last+1;
}
/* check range of digits */
for (n=0; n<bn->ndigits; n++)
if (bn->digits[n] >= bn->base)
return 1;
return 0;
}
/* print based number */
void print_bnumber(bnumber_t *bn) {
char chbase;
int n;
if (bn->base > 16) {
for (n=bn->ndigits-1; n>=0; n--)
printf("%d%c", bn->digits[n], (n>0)?DIGIT_DELIMITER:BASE_DELIMITER);
printf("%d\n", bn->base);
}
else {
switch (bn->base) {
case 2: chbase = 'b'; break;
case 8: chbase = 'o'; break;
case 16: chbase = 'h'; break;
case 10: chbase = 0; break;
default: chbase = BASE_DELIMITER; break;
}
for (n=bn->ndigits-1; n>=0; n--)
printf("%c", ((bn->digits[n]<10)?'0':('A'-10))+bn->digits[n]);
if (chbase)
printf("%c", chbase);
if (chbase == BASE_DELIMITER)
printf("%d", bn->base);
printf("\n");
}
}
/* copy based number */
void copy_bn(bnumber_t *obn, const bnumber_t *ibn) {
int i;
obn->base = ibn->base;
obn->ndigits = ibn->ndigits;
for (i=0; i < ibn->ndigits; i++)
obn->digits[i] = ibn->digits[i];
}
/* compare based number */
int cmp_bn(const bnumber_t *ib1, const bnumber_t *ib2) {
int i;
for (i=ib1->ndigits-1; i>=0; i--)
if (ib1->digits[i] != ib2->digits[i])
return 1;
return 0;
}
/* subtract based number */
void sub_bn(bnumber_t *obn, const bnumber_t *ib1, const bnumber_t *ib2) {
int i, delta, carry=0;
obn->base = ib1->base;
obn->ndigits = ib1->ndigits;
for (i=0; i < ib1->ndigits; i++) {
delta = ib1->digits[i] - (ib2->digits[i] + carry);
if (delta < 0) {
delta += ib1->base;
carry = 1;
}
else
carry = 0;
obn->digits[i] = delta;
}
}
/* sorting with simple bubble sort */
void sort_bn(bnumber_t *obn, const bnumber_t *ibn, enum so_t so) {
int i, j, t, sign;
copy_bn(obn, ibn);
sign = (so==DESCENDING)?-1:1;
for (i=0; i < obn->ndigits-1; i++)
for (j=0; j<obn->ndigits-i-1; j++)
if (sign*obn->digits[j] > sign*obn->digits[j+1])
swap(obn->digits[j], obn->digits[j+1], t);
}
/* main */
int main(int argc, char **argv) {
char instr[256];
bnumber_t d, d1, d2, dn;
int count = 0;
/* show help */
if (argc > 1)
if ((strcmp(argv[1], "-h")==0) || (strcmp(argv[1], "help")==0)) {
print_usage();
exit(EXIT_SUCCESS);
}
/* input number (w/o checking) */
printf("max. %d-stellige Zahl eingeben: ", MAX_DIGITS_SIZE);
scanf("%s", instr);
if (get_bnumber(instr, &dn) != 0) {
fprintf(stderr, "Illegal number format!\n");
exit(EXIT_FAILURE);
}
print_bnumber(&dn);
/* iteration */
do {
count++;
copy_bn(&d, &dn);
sort_bn(&d1, &dn, ASCENDING);
sort_bn(&d2, &dn, DESCENDING);
sub_bn(&dn, &d1, &d2);
print_bnumber(&dn);
} while (cmp_bn(&d, &dn) && count <= MAX_ITERATIONS);
if (count > MAX_ITERATIONS)
printf("Keine Konvergenz nach %d Iterationen.\n", MAX_ITERATIONS);
else {
printf("Die Kaprekar-Konstante (%d Iterationen) ist:\n", count);
print_bnumber(&d);
}
return 0;
}
Kommentare:
Für diese Lösung gibt es noch keinen Kommentar
Seite 1 von 0
1
