C Rotieren in der ASCII-Tabelle

Stannis

Lieutenant
Registriert
Juli 2011
Beiträge
549
Ich möchte ein kleines Programm schreiben, um die Ziffern 0-9 zeichenweise um 5 zu verschieben. 0->5, 3->8, 5->0, 6->1 usw.

Ich habe gerade einen monströsen Knoten im Hirn.... Wie schiebe Ich das?

Code:
int encodeDigit(int ch)
{	return (ch+5)%('9'+1)+'0';
}

Ich müsste doch erst 5 auf den ascii-wert addieren, dann modulo mit der Anzahl der darstellbaren Zeichen und dann wieder mit einer Addition in der Tabelle nach oben schieben, oder nicht?
So funktioniert es jedenfalls nicht. Zweifach angewendet müsste ja wieder die Ausgangsziffer rauskommen.
 
Das Problem ist dass die Zahlen in der ASCII-Tabelle nicht 0-9 sind, sondern 48-57.
Das heißt du musst 48 auf 53 werfen, dann wieder die 53 auf 48.
Also (innerhalb der ASCII-Werte):
48 -> 53 , ... , 52 -> 57 , 53 -> 48 , ... , 57 -> 52

Lösung gibts aber keine von mir :p
 
Das weiß Ich (natürlich). Sieh dir meinen Code an, da versuche Ich ja '0' draufzuaddieren, das interpretiert der Compiler dann als 48.

Im Prinzip ist das ein sehr einfaches Problem, Ich weiß, aber Ich hänge hier schon tausend Jahre :0
 
Richtig, die '0' entspricht einer 48. Dementsprechend rechnest du in deiner Modulo-Rechnung auch mod 58.
Das problem ist jetzt, wenn du '0' eingibst, bleibt es nach der Modulo Rechnung '5', auf die du dann noch eine '0' aufrechnest.
Du möchtest aber auf die '0' nicht '5' aufrechnen, sondern 5

Edit zum verdeutlichen:
'x' steht jetzt für den char, ohne ' für die Zahl als solche
 
Zuletzt bearbeitet:
Was kommt denn raus bei deiner funktion? was genau geht nicht?
wieso willst du in char rechnen wenn du integer rein gibst und wieder raus?
 
Wieso gehst du denn überhaupt über char/ASCII und nicht direkt mod auf int?
Code:
return (ch+5) % 10;
 
powerfx schrieb:
Code:
return (ch+5) % 10;
Falsch!


Code:
int encodeDigit(int ch)
{
    return ((ch-'0'+5)%10)+'0';
}
(Edit: hgader: Du hast schneller als ich getippt, kein Wunder Du hattest auch weniger Text ;-) !)

Also zuerst '0' abziehen, um in den Bereich von 0..9 zu kommen, dann 5 addieren und den Modulo-Operator anwenden, zuletzt wieder '0' addieren um daraus ASCII zu machen.

Anmerkung: Zusätzlich sollte noch Code rein um die Fälle (ch<48) und/oder (ch>57) abzufangen.


HTH

BigNum
 
Zuletzt bearbeitet: (hgader hat schneller getippt!)
@BigNum: Die main() fängt sowas schon ab ;)
Ich muss mit "-'0' " auf den ascii-Wert 0 runter, damit die modulo-operation richtig funktioniert, ja?

powerfx schrieb:
Wieso gehst du denn überhaupt über char/ASCII und nicht direkt mod auf int?
Code:
return (ch+5) % 10;
Was meinst du?
Ob Ich '0' oder 48 schreibe ist ja synonym.

hgader schrieb:
Versuch mal
return( ((ch - 48 +5) % 10 ) + 48 );

Das hatte Ich glaube Ich vorhin auch mal probiert, zumindest ähnlich. Die Frage ist, wie kommt man darauf. Warum ziehst du im ersten Schritt 48 ab?
 
Stannis schrieb:
Was meinst du?
Ob Ich '0' oder 48 schreibe ist ja synonym.
Naja, es könnte vielleicht sinnvoller sein, der Funktion den Wert als int zu übergeben (je nachdem wie der Rest aussieht). Sonst musst du hast davor und danach umrechnen.
Code:
return (ch-48+5)%10+48;
oder wenn du das lieber siehst, eben
Code:
return (ch-'0'+5)%10+'0';
 
Stannis schrieb:
Das hatte Ich glaube Ich vorhin auch mal probiert, zumindest ähnlich. Die Frage ist, wie kommt man darauf. Warum ziehst du im ersten Schritt 48 ab?
Siehe meine Erkärung in Beitrag #8
 
Hallo Stanis,

im ersten Schritt bringe ich mit -48 den ASCII char ch auf einen echten integer im Zahlenraum 0 bis 9.
Somit kann man schön die 5 addieren und modulo 10 rechnen. Am Ende addiere ich die 48 um
den integer wieder in den ASCII Raum zu verschieben.

LG,
Helmut
 
Ok, Ich glaube, damit kann Ich etwas anfangen. Danke.

powerfx schrieb:
Naja, es könnte vielleicht sinnvoller sein, der Funktion den Wert als int zu übergeben (je nachdem wie der Rest aussieht). Sonst musst du hast davor und danach umrechnen.

Der Funktion wird ein int übergeben, siehe Quellcode ;) Vielleicht verwirrt dich der Variablenname "ch".
 
Ich meine einen "echten" int. :)
Es ist ja C, deswegen kannst du das überhaupt so machen. Du verstehst doch die simple Mathematik aus #6. Wenn du jetzt aber stattdessen entsprechende chars hast, musst du sie eben zuerst zu ints umwandeln (–48) und am Ende - falls du wieder char-Werte brauchst - zurückwandeln (+48).
 
Denke diese Beispiele sollten die Rechnungen klar machen!

// Eingabe als int 0 - 9 ausgabe als 0 - 9
ch = 5
5+5 = 10
10 % 10 = 0
return 0 <- Ausgabe

ch = 0
0+5 = 5
5 % 10 = 5
return 5 <- Ausgabe


// Eingabe als char wert 48-57 Ausgabe als char Wert rechnen mit modulo 10
ch = 53
53+5 = 58
58-48 = 10
10 % 10 = 0
0 + 48 = 48 <- Ausgabe

ch = 48
48+5 = 53
53-48 = 5
5 % 10 = 5
5 + 48 = 53 <- Ausgabe


// Eingabe als char wert 48-57 Ausgabe als char Wert rechnen mit modulo 58
ch = 53
53 + 5 = 58
58 % 58 = 0
0 + 48 = 48 <- Ausgabe

ch = 48
48 + 5 = 53
53 % 58 = 5
5 + 48 = 53 <- Ausgabe
 
Stannis schrieb:
Ich habe gerade einen monströsen Knoten im Hirn.... Wie schiebe Ich das?

Ist ja eigentlich schon alles erklärt, ich bin zu spät eingestiegen um noch wirklich mitspielen zu können. Eine andere Variante wäre die Verwendung einer sog. lookup table. Hier die zwei Möglichkeiten:
Code:
 int encodeDigit_lut(int ch) {
   int lut[] = {5,6,7,8,9,0,1,2,3,4};
   return (ch & 0xf)[lut] | 0x30;
 }

 int encodeDigit_bin(int ch) {
    return  (ch + 5 - '0') % 0xa + '0';
 }
 
@blöderidiot: Warum verwendest du die index[array] Syntax, statt der array[index]? Das führt doch nur zu Verwirrung und kein Mensch kann das lesen, weil niemand diese Syntax verwendet.

Gruß
BlackMark
 
BlackMark schrieb:
Warum verwendest du die index[array] Syntax, statt der array[index]? Das führt doch nur zu Verwirrung und kein Mensch kann das lesen, weil niemand diese Syntax verwendet.

Hmmmm, hab ich hier "automatisch" so gemacht. Schreib mal bitte beide Indexvarianten untereinander - dann sollte die von mir gewählte schöner bzw. übersichtlicher aussehen. Na ok, vielleicht auch nicht. Die arr[n]-Schreibweise ist auch nur "syntactic sugar" für den direkten Speicherzugriff [arr + n] - das kann man in C auf vielerlei Art ausdrücken.
 
Also [arr + n] ist keine gültige Syntax. arr[n] und n[arr] sind equivalent zu *(arr + n) und natürlich ist + kommutativ also auch zu *(n + arr).

Ich würde das so schreiben und finde das weit lesbarer und einfacher zu verstehen als deinen Code. Das bitwise or und 0x30 sind schon sehr verwirrend und nicht einfach zu lesen.
Code:
int encodeDigit_lut( int ch )
{
	int lut[] = { 5, 6, 7, 8, 9, 0, 1, 2, 3, 4 };
	return lut[ch - '0'] + '0';
}

Gruß
BlackMark
 
Ich möchte der Vollständigkeit halber noch hinzufügen, dass man auch eine Version bauen kann, die ganz ohne langsame Division oder Speicherzugriff auskommt:
Code:
int rot_if(int ch)
{
    if (ch > '4')
        return ch - 5;
    else
        return ch + 5;
}
Das sollte meinen Vermutungen nach auf einer standardmäßigen x86-Architektur auch die schnellste Version sein. Die LUT-Version kann man vermutl. noch beschleunigen, wenn man die LUT als "static" deklariert, damit sie nicht als Instruktionen in der Assembly landet.
 
Zurück
Oben