Mathematik/Programmiertechnik zum Wochenende – Lösung
bearbeitet von
@@Matthias Apsel
> Man ermittle alle Zahlen _n_, für die gilt _n_ = _z_.
Aus der Bildungsvorschrift von *z* ergibt sich, dass *z* maximal 10stellig sein kann. Damit können auch die gesuchten mit *z* übereinstimmenden *n* maximal 10stellig sein.
Auf die Suche!
Eine Methode, um die Vorkommen eines Zeichens (einer Zeichenkette) in einem String zu zählen:
```js
String.prototype.occurrences = function (character) {
return this.match(new RegExp(character, 'g'))?.length || 0;
};
```
Ist es eigentlich eine gute oder eine blöde Idee, Basisobjekte prototypisch zu erweitern? (Ernsthafte Frage.)
Damit erhält man *z*(*n*):
```js
const z = n => {
const nString = n.toString();
let zString = '';
for (let digit = 0; digit <= 9; digit++) {
zString += nString.occurrences(digit);
}
return Number.parseInt(zString, 10);
};
```
Jetzt braucht man nur noch alle maximal 10stelligen Zahlen untersuchen:
```js
for (let n = 0; n < 1e10; n++) {
if (n == z(n)) {
console.log(n);
}
}
```
(Die nicht in *N* einthalten Zahlen 1111111111 (zehn Einsen), 2222222222, …, 9999999999 würde man einfach ignorieren, sollten sie Treffer sein.)
Das Problem daran: Das Script läuft eeeeeeeeeewig. Bzw.: Es tut es nicht; der Browser fragt immer wieder nach, ob er es weiter ausführen soll. Es läuft durch bis 10⁶; mit wiederholten Aufforderungen weiterzumachen kommt man auch bei 10⁷ zum Ende. Aber bis 10¹⁰ sind’s noch Größenordnungen …
Andere Implementierungen mögen schneller sein und keine Nachfrage erzeugen; 10¹⁰ Schleifendurchläufe sind auch dann kaum praktikabel. (Bei nur einer Zehntelmillisekunde pro Durchlauf würde das Script 10⁶ Sekunden laufen; das sind über 11½ Tage.)
Aber wir wissen schon mal, dass es keine Zahl *n* = *z*(*n*) gibt, die 7 oder weniger Stellen hat.
Das muss anders gehen als mit *brute force*{:@en}; Gewalt ist keine Lösung.
---
Ich hatte mich schon gefragt, ob ich mit *„Ich habe zwei Zahlen gefunden, für die n = z(z(n)) gilt“* nicht schon zu viel vom Lösungsweg verraten hatte …
Lassen wir uns doch mal *z*(*n*) ausgeben:
```js
const check = n => {
console.log(n, n == z(n) ? '🌞🌞🌞' : z(n));
}
```
Für 0:
```js
check(0); // 0 1000000000
```
Und jetzt setzen wir das Ergebnis wieder ein:
```js
check(1000000000); // 1000000000 9100000000
```
Und wieder und wieder:
```js
check(9100000000); // 9100000000 8100000001
```
```js
check(8100000001); // 8100000001 7200000010
```
```js
check(7200000010); // 7200000010 7110000100
```
```js
check(7110000100); // 7110000100 6300000100
```
```js
check(6300000100); // 6300000100 7101001000
```
```js
check(7101001000); // 7101001000 6300000100
```
Wir landen im Zyklus 6300000100 ↔︎ 7101001000.
Und dasselbe passiert auch für den Startwert 1, 2, 3, …, 98765, …
Das legt die Vermutung nahe, dass das für alle Startwerte so ist, d.h. dass es keine Zahl gibt, für die *n* = *z*(*n*) gilt.
An der Stelle kommt @Matthias Apsel ins Spiel, der mir zuflüsterte, dass es doch eine solche Zahl gibt. Dann heißt’s wohl, die Nadel im Heuhaufen zu suchen …
---
Und dafür eine Funktion geschrieben, die *z*(*z*(*z*(…))) berechnet, bis sie in den Zyklus läuft oder nach einigen Durchläufen abbricht. (Wie wir gesehen hatten, kommt man recht schnell in den Zyklus; 10 Schleifen sollten reichen.)
```js
attractor = n => {
for (let i = 0; i < 10; i++) {
if (n == 7101001000) {
return n;
}
else {
n = z(n);
}
}
return null;
};
```
```js
console.log(attractor(0)); // 7101001000
```
Voller Verzweiflung hab ich dann wahllos auf der Tastatur rumgeklimpert (ich schwör’s, so war’s):
```js
console.log(attractor(42189658268)); // null
```
Nanu? Reichen 10 Schleifen doch nicht? Auf 100 erhöht, 1000, 10000 – selbes Ergebnis.
Huch, was’n da los?
```js
check(42189658268); // 42189658268 120112031
```
```js
check(120112031); // 120112031 2421000000
```
```js
check(2421000000); // 2421000000 6120100000
```
```js
check(6120100000); // 6120100000 6210001000
```
```js
check(6210001000); // 6210001000 "🌞🌞🌞"
```
*Punker Maria, du ich hab die Nadel gefunden!* ([Didi](https://www.youtube.com/watch?v=izmKUc82D1s))
Es gibt sie wirklich: 6210001000 ist so eine gesuchte Zahl mit *n* = *z*(*n*).
---
Jetzt stellt sich die Frage, ob ich einfach nur wahnsinnig viel Glück hatte oder ob es viele Startwerte gibt, die nicht in den Zyklus 6300000100 ↔︎ 7101001000, sondern zu 6210001000 führen.
Die Funktion abgewandelt zu
```js
attractor = n => {
const attractors = [
6210001000,
7101001000,
];
for (let i = 0; i < 10; i++) {
if (attractors.includes(n)) {
return n;
}
else {
n = z(n);
}
}
return null;
};
```
und mit 10000 Zufallszahlen aus dem Bereich [0, 10¹⁰[ geprüft ergibt: Etwa 34½ % der Zahlen führen zu 6210001000; 65½ % zum Zylus 7101001000 ↔︎ 6300000100. Es war keine Zahl dabei, die nicht zu einem der beiden führt.
Das ist ein Indiz, aber kein Beweis dafür, dass es nicht noch weitere Zyklen gibt; womöglich gar welche der Länge 1, d.h. weitere Zahlen mit der Eigenschaft *n* = *z*(*n*).
Um das auszuschließen, fiele mir jetzt wieder nur *brute force*{:@en} ein …
Es war also doch nicht *die* Nadel, die ich im Heuhaufen gefunden hab; es gibt viele davon. Warum ich anfangs keine gefunden hatte: es gibt keine Nadeln < 10⁶. Die kleinste Zahl, die zu 6210001000 führt, ist 1000123.
Hier noch der Link zu [meiner Spielwiese](https://codepen.io/gunnarbittersmann/pen/dyYVaRV?editors=0011).
🖖 Stay hard! Stay hungry! Stay alive! **Stay home!**
{:@en}
--
Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. ([@Grantscheam](https://twitter.com/Grantscheam/status/1247046064504537092))
> Man ermittle alle Zahlen _n_, für die gilt _n_ = _z_.
Aus der Bildungsvorschrift von *z* ergibt sich, dass *z* maximal 10stellig sein kann. Damit können auch die gesuchten mit *z* übereinstimmenden *n* maximal 10stellig sein.
Auf die Suche!
Eine Methode, um die Vorkommen eines Zeichens (einer Zeichenkette) in einem String zu zählen:
```js
String.prototype.occurrences = function (character) {
return this.match(new RegExp(character, 'g'))?.length || 0;
};
```
Ist es eigentlich eine gute oder eine blöde Idee, Basisobjekte prototypisch zu erweitern? (Ernsthafte Frage.)
Damit erhält man *z*(*n*):
```js
const z = n => {
const nString = n.toString();
let zString = '';
for (let digit = 0; digit <= 9; digit++) {
zString += nString.occurrences(digit);
}
return Number.parseInt(zString, 10);
};
```
Jetzt braucht man nur noch alle maximal 10stelligen Zahlen untersuchen:
```js
for (let n = 0; n < 1e10; n++) {
if (n == z(n)) {
console.log(n);
}
}
```
(Die nicht in *N* einthalten Zahlen 1111111111 (zehn Einsen), 2222222222, …, 9999999999 würde man einfach ignorieren, sollten sie Treffer sein.)
Das Problem daran: Das Script läuft eeeeeeeeeewig. Bzw.: Es tut es nicht; der Browser fragt immer wieder nach, ob er es weiter ausführen soll. Es läuft durch bis 10⁶; mit wiederholten Aufforderungen weiterzumachen kommt man auch bei 10⁷ zum Ende. Aber bis 10¹⁰ sind’s noch Größenordnungen …
Andere Implementierungen mögen schneller sein und keine Nachfrage erzeugen; 10¹⁰ Schleifendurchläufe sind auch dann kaum praktikabel. (Bei nur einer Zehntelmillisekunde pro Durchlauf würde das Script 10⁶ Sekunden laufen; das sind über 11½ Tage.)
Aber wir wissen schon mal, dass es keine Zahl *n* = *z*(*n*) gibt, die 7 oder weniger Stellen hat.
Das muss anders gehen als mit *brute force*{:@en}; Gewalt ist keine Lösung.
---
Ich hatte mich schon gefragt, ob ich mit *„Ich habe zwei Zahlen gefunden, für die n = z(z(n)) gilt“* nicht schon zu viel vom Lösungsweg verraten hatte …
Lassen wir uns doch mal *z*(*n*) ausgeben:
```js
const check = n => {
console.log(n, n == z(n) ? '🌞🌞🌞' : z(n));
}
```
Für 0:
```js
check(0); // 0 1000000000
```
Und jetzt setzen wir das Ergebnis wieder ein:
```js
check(1000000000); // 1000000000 9100000000
```
Und wieder und wieder:
```js
check(9100000000); // 9100000000 8100000001
```
```js
check(8100000001); // 8100000001 7200000010
```
```js
check(7200000010); // 7200000010 7110000100
```
```js
check(7110000100); // 7110000100 6300000100
```
```js
check(6300000100); // 6300000100 7101001000
```
```js
check(7101001000); // 7101001000 6300000100
```
Wir landen im Zyklus 6300000100 ↔︎ 7101001000.
Und dasselbe passiert auch für den Startwert 1, 2, 3, …, 98765, …
Das legt die Vermutung nahe, dass das für alle Startwerte so ist, d.h. dass es keine Zahl gibt, für die *n* = *z*(*n*) gilt.
An der Stelle kommt @Matthias Apsel ins Spiel, der mir zuflüsterte, dass es doch eine solche Zahl gibt. Dann heißt’s wohl, die Nadel im Heuhaufen zu suchen …
---
Und dafür eine Funktion geschrieben, die *z*(*z*(*z*(…))) berechnet, bis sie in den Zyklus läuft oder nach einigen Durchläufen abbricht. (Wie wir gesehen hatten, kommt man recht schnell in den Zyklus; 10 Schleifen sollten reichen.)
```js
attractor = n => {
for (let i = 0; i < 10; i++) {
if (n == 7101001000) {
return n;
}
else {
n = z(n);
}
}
return null;
};
```
```js
console.log(attractor(0)); // 7101001000
```
Voller Verzweiflung hab ich dann wahllos auf der Tastatur rumgeklimpert (ich schwör’s, so war’s):
```js
console.log(attractor(42189658268)); // null
```
Nanu? Reichen 10 Schleifen doch nicht? Auf 100 erhöht, 1000, 10000 – selbes Ergebnis.
Huch, was’n da los?
```js
check(42189658268); // 42189658268 120112031
```
```js
check(120112031); // 120112031 2421000000
```
```js
check(2421000000); // 2421000000 6120100000
```
```js
check(6120100000); // 6120100000 6210001000
```
```js
check(6210001000); // 6210001000 "🌞🌞🌞"
```
*Punker Maria, du ich hab die Nadel gefunden!* ([Didi](https://www.youtube.com/watch?v=izmKUc82D1s))
Es gibt sie wirklich: 6210001000 ist so eine gesuchte Zahl mit *n* = *z*(*n*).
---
Jetzt stellt sich die Frage, ob ich einfach nur wahnsinnig viel Glück hatte oder ob es viele Startwerte gibt, die nicht in den Zyklus 6300000100 ↔︎ 7101001000, sondern zu 6210001000 führen.
Die Funktion abgewandelt zu
```js
attractor = n => {
const attractors = [
6210001000,
7101001000,
];
for (let i = 0; i < 10; i++) {
if (attractors.includes(n)) {
return n;
}
else {
n = z(n);
}
}
return null;
};
```
und mit 10000 Zufallszahlen aus dem Bereich [0, 10¹⁰[ geprüft ergibt: Etwa 34½ % der Zahlen führen zu 6210001000; 65½ % zum Zylus 7101001000 ↔︎ 6300000100. Es war keine Zahl dabei, die nicht zu einem der beiden führt.
Das ist ein Indiz, aber kein Beweis dafür, dass es nicht noch weitere Zyklen gibt; womöglich gar welche der Länge 1, d.h. weitere Zahlen mit der Eigenschaft *n* = *z*(*n*).
Um das auszuschließen, fiele mir jetzt wieder nur *brute force*{:@en} ein …
Es war also doch nicht *die* Nadel, die ich im Heuhaufen gefunden hab; es gibt viele davon. Warum ich anfangs keine gefunden hatte: es gibt keine Nadeln < 10⁶. Die kleinste Zahl, die zu 6210001000 führt, ist 1000123.
Hier noch der Link zu [meiner Spielwiese](https://codepen.io/gunnarbittersmann/pen/dyYVaRV?editors=0011).
🖖 Stay hard! Stay hungry! Stay alive! **Stay home!**
{:@en}
--
Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. ([@Grantscheam](https://twitter.com/Grantscheam/status/1247046064504537092))
Mathematik/Programmiertechnik zum Wochenende – Lösung
bearbeitet von
@@Matthias Apsel
> Man ermittle alle Zahlen _n_, für die gilt _n_ = _z_.
Aus der Bildungsvorschrift von *z* ergibt sich, dass *z* maximal 10stellig sein kann. Damit können auch die gesuchten mit *z* übereinstimmenden *n* maximal 10stellig sein.
Auf die Suche!
Eine Methode, um die Vorkommen eines Zeichens (einer Zeichenkette) in einem String zu zählen:
```js
String.prototype.occurrences = function (character) {
return this.match(new RegExp(character, 'g'))?.length || 0;
};
```
Ist es eigentlich eine gute oder eine blöde Idee, Basisobjekte prototypisch zu erweitern? (Ernsthafte Frage.)
Damit erhält man *z*(*n*):
```js
const z = n => {
const nString = n.toString();
let zString = '';
for (let digit = 0; digit <= 9; digit++) {
zString += nString.occurrences(digit);
}
return Number.parseInt(zString, 10);
};
```
Jetzt braucht man nur noch alle maximal 10stelligen Zahlen untersuchen:
```js
for (let n = 0; n < 1e10; n++) {
if (n == z(n)) {
console.log(n);
}
}
```
(Die nicht in *N* einthalten Zahlen 1111111111 (zehn Einsen), 2222222222, …, 9999999999 würde man einfach ignorieren, sollten sie Treffer sein.)
Das Problem daran: Das Script läuft eeeeeeeeeewig. Bzw.: Es tut es nicht; der Browser fragt immer wieder nach, ob er es weiter ausführen soll. Es läuft durch bis 10⁶; mit wiederholten Aufforderungen weiterzumachen kommt man auch bei 10⁷ zum Ende. Aber bis 10¹⁰ sind’s noch Größenordnungen …
Andere Implementierungen mögen schneller sein und keine Nachfrage erzeugen; 10¹⁰ Schleifendurchläufe sind auch dann kaum praktikabel. (Bei nur einer Zehntelmillisekunde pro Durchlauf würde das Script 10⁶ Sekunden laufen; das sind über 11½ Tage.)
Aber wir wissen schon mal, dass es keine Zahl *n* = *z*(*n*) gibt, die 7 oder weniger Stellen hat.
Das muss anders gehen als mit *brute force*{:@en}; Gewalt ist keine Lösung.
---
Ich hatte mich schon gefragt, ob ich mit *„Ich habe zwei Zahlen gefunden, für die n = z(z(n)) gilt“* nicht schon zu viel vom Lösungsweg verraten hatte …
Lassen wir uns doch mal *z*(*n*) ausgeben:
```js
const check = n => {
console.log(n, n == z(n) ? '🌞🌞🌞' : z(n));
}
```
Für 0:
```js
check(0); // 0 1000000000
```
Und jetzt setzen wir das Ergebnis wieder ein:
```js
check(1000000000); // 1000000000 9100000000
```
Und wieder und wieder:
```js
check(9100000000); // 9100000000 8100000001
```
```js
check(8100000001); // 8100000001 7200000010
```
```js
check(7200000010); // 7200000010 7110000100
```
```js
check(7110000100); // 7110000100 6300000100
```
```js
check(6300000100); // 6300000100 7101001000
```
```js
check(7101001000); // 7101001000 6300000100
```
Wir landen im Zyklus 6300000100 ↔︎ 7101001000.
Und dasselbe passiert auch für den Startwert 1, 2, 3, …, 98765, …
Das legt die Vermutung nahe, dass das für alle Startwerte so ist, d.h. dass es keine Zahl gibt, für die *n* = *z*(*n*) gilt.
An der Stelle kommt @Matthias Apsel ins Spiel, der mir zuflüsterte, dass es doch eine solche Zahl gibt. Dann heißt’s wohl, die Nadel im Heuhaufen zu suchen …
---
Und dafür eine Funktion geschrieben, die *z*(*z*(*z*(…))) berechnet, bis sie in den Zyklus läuft oder nach einigen Durchläufen abbricht. (Wie wir gesehen hatten, kommt man recht schnell in den Zyklus; 10 Schleifen sollten reichen.)
```js
attractor = n => {
for (let i = 0; i < 10; i++) {
if (n == 7101001000) {
return n;
}
else {
n = z(n);
}
}
return null;
};
```
```js
console.log(attractor(0)); // 7101001000
```
Voller Verzweiflung hab ich dann wahllos auf der Tastatur rumgeklimpert (ich schwör’s, so war’s):
```js
console.log(attractor(42189658268)); // null
```
Nanu? Reichen 10 Schleifen doch nicht? Auf 100 erhöht, 1000, 10000 – selbes Ergebnis.
Huch, was’n da los?
```js
check(42189658268); // 42189658268 120112031
```
```js
check(120112031); // 120112031 2421000000
```
```js
check(2421000000); // 2421000000 6120100000
```
```js
check(6120100000); // 6210001000 "🌞🌞🌞"
```
*Punker Maria, du ich hab die Nadel gefunden!* ([Didi](https://www.youtube.com/watch?v=izmKUc82D1s))
Es gibt sie wirklich: 6210001000 ist so eine gesuchte Zahl mit *n* = *z*(*n*).
---
Jetzt stellt sich die Frage, ob ich einfach nur wahnsinnig viel Glück hatte oder ob es viele Startwerte gibt, die nicht in den Zyklus 6300000100 ↔︎ 7101001000, sondern zu 6210001000 führen.
Die Funktion abgewandelt zu
```js
attractor = n => {
const attractors = [
6210001000,
7101001000,
];
for (let i = 0; i < 10; i++) {
if (attractors.includes(n)) {
return n;
}
else {
n = z(n);
}
}
return null;
};
```
und mit 10000 Zufallszahlen aus dem Bereich [0, 10¹⁰][ geprüft ergibt: Etwa 34½ % der Zahlen führen zu 6210001000; 65½ % zum Zylus 7101001000 ↔︎ 6300000100. Es war keine Zahl dabei, die nicht zu einem der beiden führt.
Das ist ein Indiz, aber kein Beweis dafür, dass es nicht noch weitere Zyklen gibt; womöglich gar welche der Länge 1, d.h. weitere Zahlen mit der Eigenschaft *n* = *z*(*n*).
Um das auszuschließen, fiele mir jetzt wieder nur *brute force*{:@en} ein …
Es war also doch nicht *die* Nadel, die ich im Heuhaufen gefunden hab; es gibt viele davon. Warum ich anfangs keine gefunden hatte: es gibt keine Nadeln < 10⁶. Die kleinste Zahl, die zu 6210001000 führt, ist 1000123.
Hier noch der Link zu [meiner Spielwiese](https://codepen.io/gunnarbittersmann/pen/dyYVaRV?editors=0011).
🖖 Stay hard! Stay hungry! Stay alive! **Stay home!**
{:@en}
--
Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. ([@Grantscheam](https://twitter.com/Grantscheam/status/1247046064504537092))
> Man ermittle alle Zahlen _n_, für die gilt _n_ = _z_.
Aus der Bildungsvorschrift von *z* ergibt sich, dass *z* maximal 10stellig sein kann. Damit können auch die gesuchten mit *z* übereinstimmenden *n* maximal 10stellig sein.
Auf die Suche!
Eine Methode, um die Vorkommen eines Zeichens (einer Zeichenkette) in einem String zu zählen:
```js
String.prototype.occurrences = function (character) {
return this.match(new RegExp(character, 'g'))?.length || 0;
};
```
Ist es eigentlich eine gute oder eine blöde Idee, Basisobjekte prototypisch zu erweitern? (Ernsthafte Frage.)
Damit erhält man *z*(*n*):
```js
const z = n => {
const nString = n.toString();
let zString = '';
for (let digit = 0; digit <= 9; digit++) {
zString += nString.occurrences(digit);
}
return Number.parseInt(zString, 10);
};
```
Jetzt braucht man nur noch alle maximal 10stelligen Zahlen untersuchen:
```js
for (let n = 0; n < 1e10; n++) {
if (n == z(n)) {
console.log(n);
}
}
```
(Die nicht in *N* einthalten Zahlen 1111111111 (zehn Einsen), 2222222222, …, 9999999999 würde man einfach ignorieren, sollten sie Treffer sein.)
Das Problem daran: Das Script läuft eeeeeeeeeewig. Bzw.: Es tut es nicht; der Browser fragt immer wieder nach, ob er es weiter ausführen soll. Es läuft durch bis 10⁶; mit wiederholten Aufforderungen weiterzumachen kommt man auch bei 10⁷ zum Ende. Aber bis 10¹⁰ sind’s noch Größenordnungen …
Andere Implementierungen mögen schneller sein und keine Nachfrage erzeugen; 10¹⁰ Schleifendurchläufe sind auch dann kaum praktikabel. (Bei nur einer Zehntelmillisekunde pro Durchlauf würde das Script 10⁶ Sekunden laufen; das sind über 11½ Tage.)
Aber wir wissen schon mal, dass es keine Zahl *n* = *z*(*n*) gibt, die 7 oder weniger Stellen hat.
Das muss anders gehen als mit *brute force*{:@en}; Gewalt ist keine Lösung.
---
Ich hatte mich schon gefragt, ob ich mit *„Ich habe zwei Zahlen gefunden, für die n = z(z(n)) gilt“* nicht schon zu viel vom Lösungsweg verraten hatte …
Lassen wir uns doch mal *z*(*n*) ausgeben:
```js
const check = n => {
console.log(n, n == z(n) ? '🌞🌞🌞' : z(n));
}
```
Für 0:
```js
check(0); // 0 1000000000
```
Und jetzt setzen wir das Ergebnis wieder ein:
```js
check(1000000000); // 1000000000 9100000000
```
Und wieder und wieder:
```js
check(9100000000); // 9100000000 8100000001
```
```js
check(8100000001); // 8100000001 7200000010
```
```js
check(7200000010); // 7200000010 7110000100
```
```js
check(7110000100); // 7110000100 6300000100
```
```js
check(6300000100); // 6300000100 7101001000
```
```js
check(7101001000); // 7101001000 6300000100
```
Wir landen im Zyklus 6300000100 ↔︎ 7101001000.
Und dasselbe passiert auch für den Startwert 1, 2, 3, …, 98765, …
Das legt die Vermutung nahe, dass das für alle Startwerte so ist, d.h. dass es keine Zahl gibt, für die *n* = *z*(*n*) gilt.
An der Stelle kommt @Matthias Apsel ins Spiel, der mir zuflüsterte, dass es doch eine solche Zahl gibt. Dann heißt’s wohl, die Nadel im Heuhaufen zu suchen …
---
Und dafür eine Funktion geschrieben, die *z*(*z*(*z*(…))) berechnet, bis sie in den Zyklus läuft oder nach einigen Durchläufen abbricht. (Wie wir gesehen hatten, kommt man recht schnell in den Zyklus; 10 Schleifen sollten reichen.)
```js
attractor = n => {
for (let i = 0; i < 10; i++) {
if (n == 7101001000) {
return n;
}
else {
n = z(n);
}
}
return null;
};
```
```js
console.log(attractor(0)); // 7101001000
```
Voller Verzweiflung hab ich dann wahllos auf der Tastatur rumgeklimpert (ich schwör’s, so war’s):
```js
console.log(attractor(42189658268)); // null
```
Nanu? Reichen 10 Schleifen doch nicht? Auf 100 erhöht, 1000, 10000 – selbes Ergebnis.
Huch, was’n da los?
```js
check(42189658268); // 42189658268 120112031
```
```js
check(120112031); // 120112031 2421000000
```
```js
check(2421000000); // 2421000000 6120100000
```
```js
check(6120100000); // 6210001000 "🌞🌞🌞"
```
*Punker Maria, du ich hab die Nadel gefunden!* ([Didi](https://www.youtube.com/watch?v=izmKUc82D1s))
Es gibt sie wirklich: 6210001000 ist so eine gesuchte Zahl mit *n* = *z*(*n*).
---
Jetzt stellt sich die Frage, ob ich einfach nur wahnsinnig viel Glück hatte oder ob es viele Startwerte gibt, die nicht in den Zyklus 6300000100 ↔︎ 7101001000, sondern zu 6210001000 führen.
Die Funktion abgewandelt zu
```js
attractor = n => {
const attractors = [
6210001000,
7101001000,
];
for (let i = 0; i < 10; i++) {
if (attractors.includes(n)) {
return n;
}
else {
n = z(n);
}
}
return null;
};
```
und mit 10000 Zufallszahlen aus dem Bereich [0, 10¹⁰
Das ist ein Indiz, aber kein Beweis dafür, dass es nicht noch weitere Zyklen gibt; womöglich gar welche der Länge 1, d.h. weitere Zahlen mit der Eigenschaft *n* = *z*(*n*).
Um das auszuschließen, fiele mir jetzt wieder nur *brute force*{:@en} ein …
Es war also doch nicht *die* Nadel, die ich im Heuhaufen gefunden hab; es gibt viele davon. Warum ich anfangs keine gefunden hatte: es gibt keine Nadeln < 10⁶. Die kleinste Zahl, die zu 6210001000 führt, ist 1000123.
Hier noch der Link zu [meiner Spielwiese](https://codepen.io/gunnarbittersmann/pen/dyYVaRV?editors=0011).
🖖 Stay hard! Stay hungry! Stay alive! **Stay home!**
{:@en}
--
Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. ([@Grantscheam](https://twitter.com/Grantscheam/status/1247046064504537092))
Mathematik/Programmiertechnik zum Wochenende – Lösung
bearbeitet von
@@Matthias Apsel
> Man ermittle alle Zahlen _n_, für die gilt _n_ = _z_.
Aus der Bildungsvorschrift von *z* ergibt sich, dass *z* maximal 10stellig sein kann. Damit können auch die gesuchten mit *z* übereinstimmenden *n* maximal 10stellig sein.
Auf die Suche!
Eine Methode, um die Vorkommen eines Zeichens (einer Zeichenkette) in einem String zu zählen:
```js
String.prototype.occurrences = function (character) {
return this.match(new RegExp(character, 'g'))?.length || 0;
};
```
Ist es eigentlich eine gute oder eine blöde Idee, Basisobjekte prototypisch zu erweitern? (Ernsthafte Frage.)
Damit erhält man *z*(*n*):
```js
const z = n => {
const nString = n.toString();
let zString = '';
for (let digit = 0; digit <= 9; digit++) {
zString += nString.occurrences(digit);
}
return Number.parseInt(zString, 10);
};
```
Jetzt braucht man nur noch alle maximal 10stelligen Zahlen untersuchen:
```js
for (let n = 0; n < 1e10; n++) {
if (n == z(n)) {
console.log(n);
}
}
```
(Die nicht in *N* einthalten Zahlen 1111111111 (zehn Einsen), 2222222222, …, 9999999999 würde man einfach ignorieren, sollten sie Treffer sein.)
Das Problem daran: Das Script läuft eeeeeeeeeewig. Bzw.: Es tut es nicht; der Browser fragt immer wieder nach, ob er es weiter ausführen soll. Es läuft durch bis 10⁶; mit wiederholten Aufforderungen weiterzumachen kommt man auch bei 10⁷ zum Ende. Aber bis 10¹⁰ sind’s noch Größenordnungen …
Andere Implementierungen mögen schneller sein und keine Nachfrage erzeugen; 10¹⁰ Schleifendurchläufe sind auch dann kaum praktikabel. (Bei nur einer Zehntelmillisekunde pro Durchlauf würde das Script 10⁶ Sekunden laufen; das sind über 11½ Tage.)
Aber wir wissen schon mal, dass es keine Zahl *n* = *z*(*n*) gibt, die 7 oder weniger Stellen hat.
Das muss anders gehen als mit *brute force*{:@en}; Gewalt ist keine Lösung.
---
Ich hatte mich schon gefragt, ob ich mit *„Ich habe zwei Zahlen gefunden, für die n = z(z(n)) gilt“* nicht schon zu viel vom Lösungsweg verraten hatte …
Lassen wir uns doch mal *z*(*n*) ausgeben:
```js
const check = n => {
console.log(n, n == z(n) ? '🌞🌞🌞' : z(n));
}
```
Für 0:
```js
check(0); // 0 1000000000
```
Und jetzt setzen wir das Ergebnis wieder ein:
```js
check(1000000000); // 1000000000 9100000000
```
Und wieder und wieder:
```js
check(9100000000); // 9100000000 8100000001
```
```js
check(8100000001); // 8100000001 7200000010
```
```js
check(7200000010); // 7200000010 7110000100
```
```js
check(7110000100); // 7110000100 6300000100
```
```js
check(6300000100); // 6300000100 7101001000
```
```js
check(7101001000); // 7101001000 6300000100
```
Wir landen im Zyklus 6300000100 ↔︎ 7101001000.
Und dasselbe passiert auch für den Startwert 1, 2, 3, …, 98765, …
Das legt die Vermutung nahe, dass das für alle Startwerte so ist, d.h. dass es keine Zahl gibt, für die *n* = *z*(*n*) gilt.
An der Stelle kommt @Matthias Apsel ins Spiel, der mir zuflüsterte, dass es doch eine solche Zahl gibt. Dann heißt’s wohl, die Nadel im Heuhaufen zu suchen …
---
Und dafür eine Funktion geschrieben, die *z*(*z*(*z*(…))) berechnet, bis sie in den Zyklus läuft oder nach einigen Durchläufen abbricht. (Wie wir gesehen hatten, kommt man recht schnell in den Zyklus; 10 Schleifen sollten reichen.)
```js
attractor = n => {
for (let i = 0; i < 10; i++) {
if (n == 7101001000) {
return n;
}
else {
n = z(n);
}
}
return null;
};
```
```js
console.log(attractor(0)); // 7101001000
```
Voller Verzweiflung hab ich dann wahllos auf der Tastatur rumgeklimpert (ich schwör’s, so war’s):
```js
console.log(attractor(42189658268)); // null
```
Nanu? Reichen 10 Schleifen doch nicht? Auf 100 erhöht, 1000, 10000 – selbes Ergebnis.
Huch, was’n da los?
```js
check(42189658268); // 42189658268 120112031
```
```js
check(120112031); // 120112031 2421000000
```
```js
check(2421000000); // 2421000000 6120100000
```
```js
check(6120100000); // 6210001000 "🌞🌞🌞"
```
*Punker Maria, du ich hab die Nadel gefunden!* ([Didi](https://www.youtube.com/watch?v=izmKUc82D1s))
Es gibt sie wirklich: 6210001000 ist so eine gesuchte Zahl mit *n* = *z*(*n*).
---
Jetzt stellt sich die Frage, ob ich einfach nur wahnsinnig viel Glück hatte oder ob es viele Startwerte gibt, die nicht in den Zyklus 6300000100 ↔︎ 7101001000, sondern zu 6210001000 führen.
Die Funktion abgewandelt zu
```js
attractor = n => {
const attractors = [
6210001000,
7101001000,
];
for (let i = 0; i < 10; i++) {
if (attractors.includes(n)) {
return n;
}
else {
n = z(n);
}
}
return null;
};
```
und mit 10000 Zufallszahlen aus dem Bereich [0, 10¹⁰] geprüft ergibt: Etwa 34½ % der Zahlen führen zu 6210001000; 65½ % zum Zylus 7101001000 ↔︎ 6300000100. Es war keine Zahl dabei, die nicht zu einem der beiden führt.
Das ist ein Indiz, aber kein Beweis dafür, dass es nicht noch weitere Zyklen gibt; womöglich gar welche der Länge 1, d.h. weitere Zahlen mit der Eigenschaft *n* = *z*(*n*).
Um das auszuschließen, fiele mir jetzt wieder nur *brute force*{:@en} ein …
Es war also doch nicht *die* Nadel, die ich im Heuhaufen gefunden hab; es gibt viele davon. Warum ich anfangs keine gefunden hatte: es gibt keine Nadeln < 10⁶. Die kleinste Zahl, die zu 6210001000 führt, ist 1000123.
Hier noch der Link zu [meiner Spielwiese](https://codepen.io/gunnarbittersmann/pen/dyYVaRV?editors=0011).
🖖 Stay hard! Stay hungry! Stay alive! **Stay home!**
{:@en}
--
Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. ([@Grantscheam](https://twitter.com/Grantscheam/status/1247046064504537092))