The naming conventions of Python's library are a bit of a mess, so we'll never get this completely consistent
http://legacy.python.org/dev/peps/pep-0008/
Python ist SCHROTT ;)
The naming conventions of Python's library are a bit of a mess, so we'll never get this completely consistent
http://legacy.python.org/dev/peps/pep-0008/
Python ist SCHROTT ;)
int main() {
const char *a = "I can feel segfaults";
printf("%c\n", (char*) * (char*) * (a+strlen(a)));
return 0;
}
Folgender Code:
#include < iostream >
#include < stdint.h >
using namespace std;
class Base {
public:
int32_t a;
};
class Derived : public Base {
public:
int32_t b;
};
class VirtualDerived : virtual public Base {
public:
int32_t c;
};
int main() {
cout << "sizeof Base " << sizeof(Base) << "\n";
cout << "sizeof Derived " << sizeof(Derived) << "\n";
cout << "sizeof VirtualDerived " << sizeof(VirtualDerived) << "\n";
return 0;
}
ergibt auf einer 32Bit Maschine folgende Ausgabe
sizeof Base 4 sizeof Derived 8 sizeof VirtualDerived 12
Die Größe der VirtualDerived Klasse ist also nicht einfach die Summer zweier 4Byte Variablen, sondern auch noch zusätzlich ein 4Byte Pointer auf die Base Klasse.
Auf einer 64Bit Maschine sind es entsprechend 16Byte
sizeof Base 4 sizeof Derived 8 sizeof VirtualDerived 16
Leute, ist sag es schon die ganze Zeit: Fortran ist eine tote Sprache.
Und damit meine ich nicht nur diese verbuggten Compiler. Oder dass es ewig braucht bis man ein neues Feature vom Compiler unterstützt wird. Im Fortran 2003 Standard sind zwar schön viele OO Ansatze festgelegt, aber ich kenne kein Compiler der den Standard nach 10 Jahre komplett unterstützt. Andere Sprachen sind schon 2 Schritte weiter.
Nein, diesmal habe ich viel bessere Argumente auf Lager. In dem Paper [1] wurden 800000 Software Projekte und 13000 Programmierer ausgewertet. Ich möchte nur zu einem Bild aus diesem Paper meine Meinung loswerden. Dieses da:
Also, man sieht hier die Wahrscheinlichkeit, mit der man die Programmiersprache wechselt, wenn ein neues Projekt angefangen wird. Weis bis blau sind niedrige Wahrscheinlichkeiten und rot bis schwarz hohe.
Die Punkte auf der Diagonalen zeigen, dass man die Sprache NICHT wechselt.
Was haben wir denn da alles:
Rote Punkte sehe ich bei allesn *Basic Sprachen. Auch bei der C-Familie mit Java, Perl, PHP, Python bleiben die Programmierer bei ihrer Sprache.
Welche Sprachen bekommen Zuwachs? Das sieht man schön an den vertikalen Balken. Also Java, C/C++ und meinetwegen noch PHP. Das sind also die view Großen wohin die Programmierer wechseln, nachdem sie erkannten, dass ihre vorherige Wahl Schrott war. Tja, wagt es nicht das Wort gegen C++ zu erheben ;) Die Sprache ist sowas von geil und wird den ganzen anderen Schrott längerfristig schon tot trampeln ;)
Wohin rennen denn die Fortran Leute? JAVA. Ach ich lach mich kaputt. Das sind doch total verschiedene Welten.
Ich wette die Auftraggeber wollten parallelisierte hoch performante Software. Haben aber keine Programmierer gefunden der was aufn Kasten hat, und der Rest kam mit der Sprache nicht klar. Also wurde es wieder Java. Das ist ja bekannt und jeder kann es. Und jetzt ärgern die sich mit ihrere total aufgeblasenen, lahmen Software rum, HäHä.
Die *Basic sprachen sind auch alle hinfällig. Zwar wechseln die Leute hier nicht, aber es kommen auch keine neuen hinzu. Die Sprache stirbt also aus, wenn auch alle *Basic Programmierer ausgestorben sind. Sehr einfach Das ;)
[1] Empirical Analysis of Programming Language Adoption; Leo A. Meyerovich; Ariel S. Rabkin
! use modulo to determine when to print progress
! not independet of called algorithm speed
! possible output:
! 0.0 % done
! 0.01 % done
! 0,02 % done
! 0,03 % done
! or only one output
! 80.0 % done
! We can do better!
subroutine variant1(n)
implicit none
integer, intent(in) :: n
integer :: i
do i=1, n
if(mod(i, 1000) == 0) write(*,*) 100.0*i/n, "% done"
! call some algorithm
! ...
end do
end subroutine
! check in every iteration if progress is 10%, 20% u.s.w.
! pro: independet of called algorithm speed
! contra: more code
! possible output:
! 10 % done
! 20 % done
! 30 % done
! 80 % done
! 90 % done
! We can do better!
subroutine variant2(n)
implicit none
integer, intent(in) :: n
integer :: i
real :: percent, thr
thr = 1.0 / n * 100.0
do i=1, n
percent = 100.0*i/n
if(percent > 10.0 .and. percent < 10.0+thr) write(*,*) "10 % done"
if(percent > 20.0 .and. percent < 20.0+thr) write(*,*) "20 % done"
if(percent > 30.0 .and. percent < 30.0+thr) write(*,*) "30 % done"
if(percent > 40.0 .and. percent < 40.0+thr) write(*,*) "40 % done"
if(percent > 50.0 .and. percent < 50.0+thr) write(*,*) "50 % done"
if(percent > 60.0 .and. percent < 60.0+thr) write(*,*) "60 % done"
if(percent > 70.0 .and. percent < 70.0+thr) write(*,*) "70 % done"
if(percent > 80.0 .and. percent < 80.0+thr) write(*,*) "80 % done"
if(percent > 90.0 .and. percent < 90.0+thr) write(*,*) "90 % done"
! call some algorithm
! ...
end do
end subroutine
! recalc threshold in every iteration
! possible output:
! 10 % done
! 20 % done
! 30 % done
! ...
! 90 % done
! almost done!
! we have to avoid duplicate code; copy&paste erros
subroutine variant3(n)
implicit none
integer, intent(in) :: n
integer :: i
real :: percent
integer :: thr
thr = 10
do i=1, n
percent = 100.0*i/n
if(percent > thr) then
write(*,*) thr, "% done"
thr = thr + 10
endif
! call some algorithm
! ...
end do
end subroutine
! to avoid duplicate code and copy&paste errors, we move the code into a class and provide a progress function as interface
module ProgressMeterClass
implicit none
private
public :: createProgressMeter
type, public :: ProgressMeter
integer, private :: n
integer, private :: thr
contains
procedure :: progress
end type
interface createProgressMeter
module procedure newProgressMeter
end interface
contains
function newProgressMeter(n) result(this)
implicit none
type(ProgressMeter) :: this
integer, intent(in) :: n
this%n = n
this%thr = 10
end function
subroutine progress(this, i)
implicit none
class(ProgressMeter), intent(inout) :: this
integer, intent(in) :: i
if(100.0*i/this%n > this%thr) then
write(*,*) this%thr, "% done"
this%thr = this%thr + 10
endif
end subroutine
end module
!> we use OO techniques. The progressmeter code is now in the ProgressMeterClass module.
!> We simply create an object of this type and call progress() on it in every iteration
subroutine variant4(n)
use ProgressMeterClass
implicit none
integer, intent(in) :: n
integer :: i
type(ProgressMeter) :: pm
! we can pass a step and filehandle variable too
pm = createProgressMeter(n)
do i=1, n
call pm%progress(i)
! call some algorithm
! ...
end do
end subroutine
program Progressmeter
implicit none
integer :: n
n = 10000000
! call variant1(n)
! call variant2(n)
! call variant3(n)
call variant4(n)
end program
Polymorphie kennt ihr ja, Grundzüge von OO;
Im groben geht das ja so
class Base {
public:
virtual void func() {
cout << "Base\n";
}
};
class Derived : public Base {
public:
virtual void func() {
cout << "Derived\n";
}
};
int main() {
Base *p = new Derived();
p->func(); // print "Derived"
}
Ich habe ein Pointer vom Type Base und dennoch wird die Funktion von Derived aufgerufen.
Das hier funktioniert allerdings auch:
int main() {
// We dont need to create the object on the heap with new
// Base *p = new Derived();
// Allocate this object on the stack
Derived d;
Base *p = &d;
p->func(); // prints "Derived" and not "Base"
}
Objekte auf dem Stack werden wesentlich schneller allokiert als auf dem Heap. Das müsste ein deutlichen Geschwindigkeitsvorteil für kleine und kurzlebende Objekte sein.
Wieviel Speicher verbraucht mein Programm? Die Frage ist nicht so einfach zu beantworten, denn es gibt kein Funktionsaufruf in C der bei jedem Compiler und jedem *unix funktioniert. Nach vielen googlen habe ich herausgefunden, dass es wohl am besten ist, die entsprechenden Datein in /proc zu parsen.
In /proc/self/status steht unter anderem auch der Speicherverbraucht dinne. Man kann auch /proc/self/statsm parsen, wenn man Lust hat.
kater@mintux:~$ gfortran -Wall -o procstat procstatus.F90 kater@mintux:~$ ./a.out VM size: 43044 kB
Das komplette Programm ist im Anhang.
procstatus.F90
Kurzes Programm, welches überpüft ob der Benutzer eine Variable "resolution" definiert hat. Wenn ja, wird versucht die Benutzereingabe in eine Zahl umzuwandeln. Wenn nein, wird ein default Wert von 1 angenommen.
Variante 1:
const QString resolution = options().text("resolution");
bool userResolution = false;
// check if user defined cellsize
qreal newCellSize = 1;
if(!resolution.isEmpty()) {
userResolution = true;
bool ok;
const qreal userCellSize = resolution.toDouble(&ok);
if(ok) {
newCellSize = userCellSize;
}
else {
qDebug() << "Cant parse user defined resolution:" << resolution;
}
}
Die Variable userResoltion ist nicht als const declariert und könnte überschrieben werden. Machen wir sie read-only!
Variante 2:
const QString resolution = options().text("resolution");
const bool userResolution = !resolution.isEmpty();
// check if user defined cellsize
qreal newCellSize = 1;
if(!resolution.isEmpty()) {
bool ok;
const qreal userCellSize = resolution.toDouble(&ok);
if(ok) {
newCellSize = userCellSize;
}
else {
qDebug() << "Cant parse user defined resolution:" << resolution;
}
}
Der Code sieht noch etwas aufgebläht aus. Trennen wir den normalen Programm Path und den Error Path, der durchlaufen wird, wenn die Benutzereingabe ungültig ist.
Variante 3:
qreal toDouble(const QString& s) throw(Exception) {
bool ok;
qreal x = s.toDouble(&ok);
if(!ok)
throw Exception("Cant convert to double" + s);
return x;
}
...
const QString resolution = options().text("resolution");
const bool userResolution = !resolution.isEmpty();
// check if user defined cellsize
qreal newCellSize;
try {
newCellSize = toDouble(resolution);
}catch(...) {
newCellSize = 1.0;
if(!resolution.isEmpty())
qDebug() << "Cant parse user defined resolution:" << resolution;
}
Nun möchten wir die Variable newCellSize auch noch read-only haben, da sie ein Parameter ist und niemals mehr geändert werden darf. Dafür lagern wir nun die komplette Logik für das Parser der Benutzereingabe in eine Funktion aus.
Variante 4:
qreal toDouble(const QString& s, qreal defaultValue = 0.0) {
if(s.isEmpty())
return defaultValue;
bool ok;
qreal x = s.toDouble(&ok);
if(!ok) {
qDebug() << "Cant convert to double" + s;
return defaultValue;
}
return x;
}
...
const QString resolution = options().text("resolution");
const bool userResolution = !resolution.isEmpty();
// check if user defined cellsize
const qreal newCellSize = toDouble(resolution, 1.0);
Der wesentliche Code ist jetzt nur noch 4 Zeilen lang, statt 15 Zeilen.
Er ist auf das wesentliche reduziert, verständlicher und gegen das versehentliche überschreiben der Variablen geschützt.
Nachteile gibt es allerdings auch. Die Fehlermeldung wenn das Konvertieren fehl schläng ist nicht anpassbar. Mit einem zustäzlichen Funktionsargument könnte man das aber nachbessern.
local$ ssh -4 -p PORT -N -L 8000:192.168.210.102:80 user@ite
Nette Sache Das! SSH bindet aber leider keine Ports an 0.0.0.0 da muss man mit netcat etwas nachhelfen
01.2018 Update: Doch das geht. Man muss nur 0.0.0.0: vorne dran setzen. Für IPv4 natürlich.
02.2019 Update2: Für IPv4 die -4 nicht vergessen. Sonst bind [::1]:10000: Cannot assign requested address
Old:
local$ ssh -p PORT -L 1391:192.168.210:41:139 user@ite -N
local$ netcat -l -p 139 -c "netcat 127.0.0.1 1391"
Mit 445 genauso.
Es gibt viele Möglichkeiten den Median zu berechnen. Eine wäre die Daten zu sortieren und dann das mittlere Element zu wählen.
Dazu muss man aber eine Kopie der Daten speichern, was ungünstig ist, wenn der Arbeitsspeicher schon fast voll ist. Jaaa, heutzutage hat jeder Unmengen an Arbeitsspeicher. Es gibt aber Menschen die haben "NUR" 2GB RAM und die sind durch die aufgeblasenen Standardprogramme (Browser, Office, Mail, Clould, Solzial) schon zu 85% belegt. Und wenn man dann noch etwas Arbeiten will und sich ein paar Datensätze visualisiert, können schon 50MB mehr zum Überlaufen des RAMs führen ;)
(50MB entsprechen ca. 7Millionen double Variabeln)
Es wäre doch toll, wenn man den Median berechnen könnte, ohne den Datensatz zu verändern oder zu kopieren!
Eine Runde googlen:
http://stackoverflow.com/questions/638030/how-to-calculate-or-approximate-the-median-of-a-list-without-storing-the-list/638713#638713
Ich hab diesen Algorithmus mal in Qt implementiert und ein wenig verändert. Bei einer grade Anzahl von Eingangsdaten berechnet er ursprüngliche Algorithmus den falschen Median. Ich habe es jetzt so geändert, dass immer das oberste der beiden mittleren Elemente im Array zurückgegeben wird. Das kann man irgendwann auch noch mal verbessern.
Noch ein Wort zur Laufzeit. Die Anzahl der Iterationen betrug bei meinem Tests meist so um die 50. Das muss eigentlich auch so sein, denn wir haben es hier mit einer binären Suche zu tun. Denn bei jeder Iteration wird der Zahlenbereich, der mit einer double precision floating number Variable dargestellt werden kann, in 2 Hälften zerlegt. So tanzt der approximierte Median immer um den echten Median herrum, bis die Zahlengenauigkeit fein genug ist.
Mit double Precision bekommt man etwa 16 Ziffern Genauigkeit. Und der 2er Logarithmus von 50 ergibt eine Zahl mit 16 Ziffern. Das passt doch :D Man muss also immer 50mal den Zahlenbereich aufteilen um an den Median zu kommen.
Bei jeder dritten Iteration bekommt man also etwa eine Ziffer an Zahlengenauigkeit dazu. Gibt man sich mit nur 8 Ziffern Genauigkeit zufrieden, braucht man auch nur 25 Iterationen.
Wir haben also einen Agorithmus dessen Laufzeit linear mit der größe des Datensatzes wächst O(n*50). Das ist doch super! Ganz anders als die Variante welches erst die Daten sortiert O(n*log(n)). In der Praxis bringt einem das aber erstmal nichts an Laufzeit. Denn wie groß muss der Datensatz werden, damit der log(n) = 50 wird? 1,125,899,906,842,624 ! Also erst ab einer Billiarden Zahlen hätten wir ein Laufzeitvorteil. Dazu bräuchte man aber auch 8000 Terrabyte an Speicherplatz :D
Gibt man sich in Qt/C++ eine Zahl in der Konsole aus, bekommt man in der Regel nur 6 Ziffern angezeigt. Das entspricht 18Iterationen. Also log(n) = 18 für n = 262,144 Hier sieht die Welt schon besser aus. Schon ab 260,000 Zahlen bekomen wir ein Laufzeitvorteil.
Wir haben also ein Algorithmus, der keinen zusätzlichen Speicherplatz braucht und auch noch in der Laufzeit einstellbar ist. Gibt man sich nur mit wenigen relevanten Ziffern des approximierten Medians zufrieden, ist die Laufzeit schon bei kleinen Datenmengen besser als die des Sortierverfahrens.
Happy coding ;)
/*
Find Min and Max of the list containing N items through linear search and name them as HighValue and LowValue Let MedianIndex = floor(N/2)
1st Order Binary Search:
Repeat the following 4 steps until LowValue < HighValue.
Get MedianValue approximately = ( HighValue + LowValue ) / 2
Get NumberOfItemsWhichAreLessThanorEqualToMedianValue = K
is K > MedianIndex ? then HighValue = MedianValue Else LowValue = MedianValue
*/
/*!
Return the median. If data has even size, not the avg of the two numbers in the
middel of the array is returned, but the upper one.
This is an improved version from
http://stackoverflow.com/questions/638030/how-to-calculate-or-approximate-the-median-of-a-list-without-storing-the-list/638713#638713
This algorithm need in practice 50 iterations. Like a binary search around the true median.
*/
qreal experimenalMedian(const QVector &data) {
if(data.isEmpty())
return 0.0;
QPair minmax = qMinMax(data);
int medianIdx = qFloor(data.size()/2.0);
qreal medianValue = (minmax.first + minmax.second)/2.0;
while(minmax.first < minmax.second &&
!fuzzyCompare(minmax.first, minmax.second)) {
medianValue = (minmax.first + minmax.second)/2.0;
int K = 0;
for(int i=0; i < data.size(); i++) {
if(data.at(i) <= medianValue) {
K++;
}
}
K > medianIdx ? minmax.second = medianValue : minmax.first = medianValue;
}
return medianValue;
}
Powered by WordPress