Ich bin auf einen faszinierenden C-Code gestoßen, der gedruckt werden kann A + B
aber ich habe Schwierigkeiten, es zu verstehen.
Eingabeformat:
A B
wo A
, B
sind ganze Zahlen zwischen 0
und 10
durch ein einzelnes Leerzeichen getrennt.
Code:
main( n )
{
gets( &n );
printf("%d", n % 85 - 43);
}
Dies war für eine kurze Codierung gedacht, beachten Sie bitte die Warnungen.
Was ich bisher verstanden habe:
gets( &n )
speichert die ASCII-Werte von A, Leerzeichen und B in den unteren drei Bytes von n
. Zum Beispiel, A = 3
und B = 8
ergäbe n = 0x00382033
. Gegebene Bedingungen verhindern n
vom Überlaufen. Aber ich verstehe nicht wie n % 85 - 43
Erträge A + B
.
Wie kommen Sie auf diese Zahlen?
Mit Little-Endian-Ints (und unter der Annahme von ASCII-Text und 8-Bit-Bytes und all den anderen Annahmen, die der Code erfordert) und dem Ignorieren all des technisch falschen in modernem C-Zeugs im Code, Ihr “Was ich verstehe bisher” ist richtig.
gets(&n)
speichert die ASCII-Werte von A, Leerzeichen und B in den ersten 3 Bytes von n
. Es speichert auch ein Null-Terminator im 4. Byte. Speichern dieser ASCII-Werte in diesen Bytes von n
ergibt sich n
Wert nehmen B*256*256 + space*256 + A
wo B
, space
und A
stellen die entsprechenden ASCII-Werte dar.
256 mod 85 ist 1, also durch die Eigenschaften der modularen Arithmetik,
(B*256*256 + space*256 + A) % 85 = (B + space + A) % 85
Übrigens, mit 4-Byte-Big-Endian-Ints erhalten wir
(A*256*256*256 + space*256*256 + B*256) % 85 = (B + space + A) % 85
Endianness spielt also keine Rolle, solange wir 4-Byte-Ints haben. (Größere oder kleinere Ints könnten ein Problem darstellen; bei 8-Byte-Ints müssten wir uns beispielsweise Gedanken darüber machen, was in den Bytes von enthalten ist n
das gets
nicht gesetzt.)
Das Leerzeichen ist ASCII 32, und der ASCII-Wert für ein Ziffernzeichen ist 48 + der Wert der Ziffer. Definieren a
und b
als numerische Werte der eingegebenen Ziffern (anstelle der ASCII-Werte der Ziffernzeichen) haben wir
(B + space + A) % 85 = (b + 48 + 32 + a + 48) % 85
= (a + b + 128) % 85
= (a + b + 43) % 85
(B + space + A) % 85 - 43 = (a + b + 43) % 85 - 43
= (a + b) % 85
= a + b
wobei die letzten beiden Äquivalenzen darauf beruhen, dass a
und b
Werte von 0 bis 9 annehmen.
In der Tat faszinierend.
– Havenar
19. Juli 2018 um 5:15 Uhr
Ein Hinweis ist, dass 85 binäre Bits sind,
01010101
. Versucht man diesen Ansatz mit10101010
das ist die Nummer 170, erhalten Sie eine ähnliche Funktionalität, der einzige Unterschied besteht darin, wenn Sie mit tun0 0
Sie erhalten stattdessen die Nummer 128 (was10000000
binär). Eine ähnliche Technik wird verwendet, um eine Reihe von Optimierungen mit bitweisen Operationen durchzuführen, z. B. das Zählen der Anzahl von Bits in einem Bitsatz unter Verwendung von Masken wie z0x55555555
und0xAAAAAAAA
(0x55 = 85 und 0xAA = 170). Wenn Sie diese Hexadezimalcodes googeln, erhalten Sie eine Reihe interessanter Artikel.– Havenar
19. Juli 2018 um 5:33 Uhr
Wow, ich hätte nie so viel Tiefe in der Zahl 85 erwartet. Danke für den Einblick.
– William Lee
19. Juli 2018 um 6:35 Uhr
Ich nehme an, Sie meinen zwischen 0 und 9 einschließlich?
– Rohr
19. Juli 2018 um 16:52 Uhr
Das ist definitiv ioccc würdig.
– dgnuff
19. Juli 2018 um 20:02 Uhr