Home

Schulzeitnostalgie,Taschenrechner und transzendente Zahlen

Montag, 16. April 2012 | Autor:

Damals™ in der Schule hat­ten wir Taschen­rech­ner. Zu Anfang eher ein ein­fa­ches Modell: Grund­re­chen­ar­ten, ele­men­tare Funk­tio­nen – passt. Spä­ter dann wech­sel­ten wir zu einem deut­lich aus­ge­feil­te­ren Modell – dem TI-83! Der kann auch Funk­tio­nen zeich­nen, nume­risch inte­grie­ren und ablei­ten, man kann mit Matri­zen rech­nen, Sta­tis­tik betrei­ben und vie­les ande­res mehr! Was mir auch sehr gut gefiel: Es gab ein dickes Hand­buch dazu, in dem alle seine Funk­tio­nen und Ein­stel­lun­gen beschrie­ben waren. Eine rich­tige gute Anlei­tung, die zum Mit­ma­chen ein­lud – ein­fach toll!

Aber das Aller­beste war: mei Mama hat Ame­ri­ka­ner bachele  Der Taschen­rech­ner war pro­gram­mier­bar! Bezie­hungs­weise ist – ich habe ihn immer noch. Im Nach­hin­ein betrach­tet, war der TI-83 wohl das, was für frü­here Gene­ra­tio­nen der C64 war: meine Ein­stiegs­droge zur Infor­ma­tik. Ich habe wirk­lich viel pro­gram­miert: In den Pau­sen, im Bus, wäh­rend des Mit­tag­es­sens. Ich habe ihn auch in den Urlaub mit­ge­nom­men! Dazu muss man wis­sen: wir hat­ten ein Wohn­mo­bil, da war der Taschen­rech­ner, der dank der Pro­gramme ande­rer auch gleich­zei­tig Spie­le­kon­sole war, ein guter Lan­ge­wei­le­kil­ler auf lan­gen Fahr­ten (Fahr­ten in Schwe­den sind immer lang). Außer­dem war das noch nicht die Zeit alles­kön­nen­der Immer-dabei-Elektronik, also konnte man den Taschen­rech­ner auch aus prak­ti­schen Grün­den recht­fer­ti­gen. Pro­gramme aus die­ser Zeit pro­to­kol­lier­ten zum Bei­spiel den Ben­zin­ver­brauch oder rech­ne­ten Wäh­run­gen um.

Aber zurück zum Thema: Das prak­ti­sche an Pro­gram­men ist ja, dass sie mono­tone Auf­ga­ben für einen über­neh­men, sodass man sich selbst ganz auf den inter­es­san­ten krea­ti­ven Part stür­zen kann! Mathe­auf­ga­ben zum Bei­spiel: Ich habe jedes Pro­blem, das wir in Mathe behan­delt haben, zeit­nah in ein Pro­gramm umge­setzt. Das ist ein­fa­cher, als es klingt, denn die meis­ten die­ser Schul-Mathematik-Dinger beste­hen ja nur aus einer ein­zel­nen Glei­chung, mei­net­we­gen die Gera­den­glei­chung oder die For­mel zur Lösung Qua­dra­ti­scher Glei­chun­gen. Typi­sche Pro­gramme sahen so aus: Der Start­bild­schirm fragte, wel­che Grö­ßen gege­ben waren. Dann wurde man gebe­ten, diese ein­zu­ge­ben. Danach rech­nete das Pro­gramm die ein­schlä­gige und pas­send umge­stellte Glei­chung aus und zeigte das Ergeb­nis an. Keine große Sache, aber eine immense Zeit­er­spar­nis! Vor allem in Klau­su­ren habe ich jede Menge Zeit gewon­nen, die ich anderswo bes­ser gebrau­chen konnte. Meine (übri­gens sehr guten) Leh­rer haben zwar auf den Lösungs­weg gepocht, aber ich habe meine Pro­gramme dann ein­fach umge­schrie­ben, sodass sie auch die Zwi­schen­schritte anzeigten.

Nun gibt es aber bei Taschen­rech­nern ein Pro­blem: Sie spu­cken so Zah­len aus wie
1.41421356
Zah­len mit begrenz­ter Genau­ig­keit ohne tie­fe­ren Sinn. Wenn man die Zah­len aber immer und immer wie­der sieht, erkennt man sie irgend­wann recht schnell. Die Zif­fern­folge 1.414… ist zum Bei­spiel meist kein Zufall, son­dern ein­fach die Wur­zel aus Zwei. Warum man das wis­sen möchte? Allein schon, um nicht immer „1.41421356“ schrei­ben zu müs­sen ;). Ein ande­rer Zweck ist fol­gen­der: Wenn man in einem Test als Ergeb­nis „1.41421356“ hin­schreibt, weiß der oder die Leh­re­rin sofort, dass man nicht selbst per Hand gerech­net hat, denn per Hand hätte man in der For­mel direkt gese­hen, dass es Wur­zel 2 ist und es auch so als Ergeb­nis angegeben!

Wenn man den Ver­dacht hat, dass eine Zahl eine Wur­zel aus irgend­was ist, kann man sie aber ein­fach im Taschen­rech­ner qua­drie­ren:

1.41421356^2
= 2
1.7320509^2
= 3.00000032

Voilà – schon weiß man Bescheid! Manch­mal kommt es nicht ganz hin. Ent­we­der hat dann die Zahl, die man qua­driert, Rechenun­ge­nau­ig­kei­ten drin oder die Zahl ist ein­fach wirk­lich nicht die Wur­zel aus 3.

Irgend­wann, wie hätte es auch anders kom­men sol­len, habe ich mir natür­lich ein Pro­gramm geschrie­ben, dass gleich meh­rere sol­cher Tricks durch­pro­biert! Ist die Zahl ein Viel­fa­ches von Pi oder e? eine Wur­zel? eine Kubik­wur­zel? das Inverse von irgend­was? Wobei die Hoff­nung natür­lich immer ist, dass die­ses Irgend­was ein­fa­cher ist. Mit „Wow, 1.7320509 ist genau das 0.637185917fache von e!“ kann man nie­man­den beeindrucken.

Lus­ti­ger­weise trei­ben sol­che Fra­gen nicht nur faule Schü­ler um, son­dern auch Mathe­ma­ti­ker. Kann man jede Zahl als Bruch zweier gan­zer Zah­len dar­stel­len? Nö, geht nicht. Die Länge der Dia­go­na­len in einem Qua­drat zum Bei­spiel nicht. Sie beträgt √2 und die ist irrational.

Irra­tio­nale Zah­len sollte jeder mal gehört haben, aber es gibt auch noch soge­nannte „tran­szen­dente“ Zah­len. Abge­fah­re­ner Name, aber was ist das? Man sollte sich in Mathe­ma­tik grund­sätz­lich nicht von Namen ein­schüch­tern las­sen, aber mir passiert’s trotz­dem immer mal wie­der. Gehen wir erst­mal noch n Stück zurück…

Mein Pro­gramm war ursprüng­lich gedacht, um Wur­zeln zu erken­nen. Das hat oft recht gut geklappt oder wenn nicht, dann war die frag­li­che Zahl meist ein Viel­fa­ches von Pi, aber las­sen wir das mal weg und kon­zen­trie­ren wir uns auf die Wur­zeln. Mit­un­ter war eben auch das Qua­drat oder Kubik einer Zahl selbst wie­derum tota­ler Zahlenwirrwar.

Bei­spiel. Wir haben aus irgend­ei­ner Berech­nung x=1.618033989 her­aus­be­kom­men und pro­bie­ren unse­ren Standardtrick:

1.618033989^2
= 2.618033989

Ohhhhh­kay­y­yyy. Das Qua­drat der Zahl ist offen­bar die­selbe (immer­noch wirre) Zahl plus 1. Das ent­spricht der Gleichung:

x² – x – 1 = 0

und 1.618033989 ist eine Lösung die­ser Glei­chung. Jetzt könnte man den­ken: „Hey! Es ist also nicht jede Zahl eine Wur­zel von irgend­was, aber viel­leicht ist ja jede Zahl eine Lösung so einer ein­fa­chen For­mel? So wie x² – x – 1 = 0?“

Die Ant­wort auf diese Frage wurde erst 1844 von Liou­ville gefun­den und lautet:

Nein.

Es gibt Zah­len, für die das nicht geht. Sie wer­den tran­szen­dente Zah­len genannt. Pi ist zum Bei­spiel eine sol­che Zahl.

Zah­len, die doch Lösung so eines Poly­noms sind, z.B. die oben genannte 1.618033989…, wer­den alge­bra­isch genannt. Aller­dings sind diese Zah­len auch nicht unbe­dingt ein­fach, da es für die Lösun­gen von Poly­no­men nicht immer eine geschlos­sene Form gibt. Dann lan­det man eben doch wie­der bei lan­gen unin­tui­ti­ven und schwer zu mer­ken­den Zah­len­ko­lon­nen – aber dafür gibt es ja dann Taschenrechner ;)

Thema: Programmieren | Beitrag kommentieren

Dateiendungen bei C++

Mittwoch, 20. Juli 2011 | Autor:

Eine Frage die ich mir damals gestellt habe: Wel­che Datei­en­dun­gen müs­sen C++-Dateien haben?

Der G++-Compiler akzep­tiert nur eine hand­voll Endun­gen1:

file.cc
file.cp
file.cxx
file.cpp
file.CPP
file.c++
file.C

Aber theo­re­tisch kann man auch .mett­bröt­chen neh­men, wenn man dem Com­pi­ler sagt, dass es C++ sein soll :D

  1. http://gcc.gnu.org/onlinedocs/gcc/Overall-Options.html

Thema: Programmieren | Beitrag kommentieren

Wahre Worte zum Vertrauen in Karten und Computer

Freitag, 27. Mai 2011 | Autor:

Bei der Recher­che zur Mas­ter­ar­beit gefun­den. Wahre Worte:

Uncer­tainty is a cri­ti­cal issue due to the ten­dency of most people to treat both maps and com­pu­ters as somehow less fal­li­ble than the humans who make deci­si­ons they are based upon.

Quelle: MacE­ach­ren: Visua­li­zing Uncer­tain Infor­ma­tion [PDF]

Thema: Informatik, Programmieren | Beitrag kommentieren

Optimierung

Dienstag, 15. Februar 2011 | Autor:

Ich mache mir oft Gedan­ken, ob mein Code „schnell” ist. Lahme und inef­fi­zi­ente Pro­gramme gibt es schließ­lich schon genug - meins dage­gen soll per­for­mant sein, jawoll!

Es gibt aller­dings ein paar Grund­re­geln beim Opti­mie­ren. Wahr­schein­lich auch mehr als nur ein paar - aber das hier sind die, die ich für mich als prak­tisch und sinn­voll her­aus­ge­fun­den habe. wei­ter…

Thema: Programmieren | Beitrag kommentieren

Ninja-Segfault

Montag, 7. Februar 2011 | Autor:

Letzte Woche hatte ich einen Bug, der mich 4 Stun­den und die ent­spre­chende Menge Ner­ven gekos­tet hat. Der Ori­gi­nal­code ist ziem­lich undurch­sich­tig, des­we­gen habe ich eine kleine, kom­pi­lier­bare Demo geschrieben:

#include <vector>
#include <stack>

class Blubb
{
	public:
		std::vector<int> * liste;
		Blubb() {
			liste = new std::vector<int>(10);
		}
		~Blubb() {
			delete liste;
		}
};

int main()
{
	std::stack<Blubb> stapel;
	Blubb blip;
	stapel.push(blip);
	return 0;
}

Wer meint, C++ zu beherr­schen, darf jetzt grü­beln, warum die­ser Code einen Seg­fault wirft. Viel Spaß dabei! ;) wei­ter…

Thema: Sezierte C++-Käfer | 2 Kommentare

Das Semikolon aus einer anderen Welt

Dienstag, 25. Januar 2011 | Autor:

#include "../../math/src/FInterpolation.hh"

/** Interface class for seed lines such as lines, curves, polylines. */
class SeedCurve
{
	public:
		virtual FPosition ipol(double t) = 0;
		virtual vector<FPosition> getPositions(positive number_of_seeds) = 0;
};

gibt eine Fehlermeldung:

SeedLine.hh:9:1: error: multiple types in one declaration

Meh­rere Typen in einer Deklaration.

Der Aus­lö­ser für diese Mel­dung ist sim­pel, aber viel­leicht nicht offen­sicht­lich: Nach der Dekla­ra­tion eines neuen „Typs”, d.h. einer Klasse oder eines Structs, wurde das Semi­ko­lon ver­ges­sen - aller­dings nicht an der Stelle, die die Feh­ler­mel­dung nennt! ;) wei­ter…

Thema: Sezierte C++-Käfer | 2 Kommentare

Lange Fehlermeldung, kleine Ursache

Mittwoch, 19. Januar 2011 | Autor:

/home/nico/code/FAnToM/src/visAlgos/StreakSurface/FStreakSurfaceAlgorithm.cc: In member function ‘void FStreakSurfaceAlgorithm::DCELtest()’:
/home/nico/code/FAnToM/src/visAlgos/StreakSurface/FStreakSurfaceAlgorithm.cc:245:43: error: no match for ‘operator<<’ in ‘std::cout << ((DCEL::HalfEdge*)((DCEL::HalfEdge*)((boost::intrusive::detail::add_const_if_c::type*)x.boost::intrusive::list_iterator::operator* [with Container = boost::intrusive::list_impl, (boost::intrusive::link_mode_type)1u, boost::intrusive::default_tag, 1>, long unsigned int, true> >, bool IsConst = false, typename boost::intrusive::detail::add_const_if_c::type& = DCEL::HalfEdge&, typename boost::intrusive::detail::add_const_if_c::type = DCEL::HalfEdge]

wei­ter…

Thema: Sezierte C++-Käfer | 2 Kommentare

Constness of least Surprise

Donnerstag, 6. Januar 2011 | Autor:

Phy­sik­stu­dent Mar­tin K.1 hat mir wie­der einen net­ten klei­nen Bug zuge­tra­gen! Hier erst­mal der Codeausschnitt:

QList<qint32> countlist;
	//std::swap funktioniert nicht, daher manuelles tauschen
	int_swap = countlist.at(i);
	countlist.at(i) = countlist.at(j);
	countlist.at(j) = int_swap;
	string_swap = keylist.at(i);
	keylist.at(i) = keylist.at(j);
	keylist.at(j) = string_swap;

Und die Fehlermeldung:

wortliste.cpp: In function 'void quick_sort(QList<QString>, QList<int>)':
wortliste.cpp:49: error: assignment of read-only location 'countlist.QList<T>::at [with T = int](i)'
wortliste.cpp:50: error: assignment of read-only location 'countlist.QList<T>::at [with T = int](j)'
wortliste.cpp:52: error: passing 'const QString' as 'this' argument of 'QString& QString::operator=(const QString&)' discards qualifiers
wortliste.cpp:53: error: passing 'const QString' as 'this' argument of 'QString& QString::operator=(const QString&)' discards qualifiers

Viel­leicht mal ein paar Worte zum Lesen von Feh­ler­mel­dun­gen. wei­ter…

  1. Name nicht im Gerings­ten geän­dert.

Thema: Sezierte C++-Käfer | Beitrag kommentieren

no matching function call

Montag, 27. Dezember 2010 | Autor:

Ein neuer Tag, eine neue Fehlermeldung:

/home/nico/code/FAnToM/src/visAlgos/IntegralLines/../../math/src/ODESolver/StreakLine.hh:76:2: error: no matching function for call to ‘Tracer<2, (FLineType)0u>::Tracer(std::vector<MeshNode>, boost::shared_ptr<const FTimeDependentTensorField>&, FPosition&, double&, const double&, const double&, int)’
/home/nico/code/FAnToM/src/visAlgos/IntegralLines/../../math/src/ODESolver/Tracer.hh:392:3: note: candidates are:
[... (diverse Vorschläge ausgelassen)]
/home/nico/code/FAnToM/src/visAlgos/IntegralLines/../../math/src/ODESolver/Tracer.hh:886:1: note:                 Tracer<DIM, lineT>::Tracer(std::vector<MeshNode>&, Tracer<DIM, lineT>::Fieldtype, const FPosition&, double, double, double, unsigned int) [with int DIM = 2, FLineType lineT = (FLineType)0u, Tracer<DIM, lineT>::Fieldtype = boost::shared_ptr<const FTimeDependentTensorField>, FPosition = FArray]

Diese Mel­dung ist aus einem ganz bestimm­ten Grund fies, der aber nicht offen­sicht­lich ist. Die Mel­dung sug­ge­riert, man habe beim Funk­ti­ons­auf­ruf etwas falsch­ge­macht. Oft stimmt das auch und die Gründe sind dann solche:

  • Para­me­ter der Funk­tion vergessen
  • bei einem (oder meh­re­ren!) Para­me­tern den fal­schen Typ benutzt
  • const igno­riert
  • Tipp­feh­ler

Ich habe über­legt, was davon es sein könnte. Gegrü­belt und getes­tet. Man fängt ja nach ner Weile an, die unmög­lichs­ten Dinge zu ver­mu­ten. Zum Bei­spiel, dass es viel­leicht daran, dass ein Para­me­ter const oder eine Refe­rence ist? Habe ich Tem­pla­tes falsch benutzt? Gerade für Anfän­ger, die mit con­st­ness, Refe­ren­zen und Tem­pla­tes noch nicht so firm sind, der Super-Gau!

Aber auch mir ist es heute passiert.

Es lag daran, dass ich die Datei, in der die Funk­tion deklariert/definiert ist, nicht inclu­det habe.

Thema: Sezierte C++-Käfer | Beitrag kommentieren

Linker-Fehler und c++filt

Dienstag, 30. November 2010 | Autor:

Linker-Error sind aus zwei Grün­den ekel­haft:
Ers­tens: Sie sind kryp­tisch sind, viel kryp­ti­scher als Com­pil­er­feh­ler (ja, das geht).
Zwei­tens: Sie tre­ten unter Umstän­den erst zur Lauf­zeit auf.

Bei­spiel:
could not load plugin './algoStore/visAlgoslibStreakSurface.so' :./algoStore/visAlgoslibStreakSurface.so: undefined symbol: _ZN23FStreakSurfaceAlgorithm10split_edgeESt4pairI6FArrayS1_E

Okay, undefined symbol - da haben wir wohl irgend­et­was dekla­riert, aber nicht defi­niert1. Aber was genau haben wir nicht defi­niert?
_ZN23FStreakSurfaceAlgorithm10split_edgeESt4pairI6FArrayS1_E?
Manch­mal kann man erra­ten, was gemeint ist, da die Namen der invol­vier­ten Funk­tio­nen, Klas­sen, Varia­blen in dem Wust irgendwo drin ste­hen. Aber eben nur manch­mal. Die Lösung die­ses Pro­blems lau­tet c++filt!

c++filt ist ein klei­nes Tool, das einem die Sym­bol­na­men ent­zif­fert! („deman­g­led”). So wird’s benutzt:

> c++filt _ZN23FStreakSurfaceAlgorithm10split_edgeESt4pairI6FArrayS1_E
FStreakSurfaceAlgorithm::split_edge(std::pair<FArray, FArray>)
>

und schon ken­nen wir den Klar­na­men des Sym­bols! Ein­fach toll - ich wünschte, ich hätte die­ses Tool schon frü­her gekannt!

  1. Dekla­ra­tion = „Es gibt diese und jene Funk­tion!” Bsp: void funktion(double k); Dekla­ra­tio­nen ste­hen typi­scher­weise in Header-Files. -- Definition/Implementation = „Die Funk­tion tut die­ses hier.” Bsp: void funktion(double k){ return 1./(k+1); } -- Man beachte, dass die Dekla­ra­tion wirk­lich eine reine Exis­tenz­be­haup­tung ist und erst die Defi­ni­tion das Ver­hal­ten der Funk­tion defi­niert, d.h. den Code ent­hält, den diese aus­führt.

Thema: Programmieren | 4 Kommentare