Ergänzung zu Yalus Tests

Gast #3882580
Ich hatte mir eben dann doch noch mal den C++ und Haskell Code etwas 
genauer angesehen und einige Tests gemacht. Die Geschwindigkeit von 
Haskell ist schon recht beeindruckend dafür, dass der Code doch recht 
abstrakt, also nicht sonderlich optimiert ist. Der C++ Code verzichtet 
ja nun auf push() und pop()-Operationen und ebenfalls auf 
Kopieroperationen, indem gleich zu Anfang ein großer Vector angelegt 
wird. Das habe ich mal in Nim nachgebildet. Und: Nim ist bei mir damit 
sogar etwas schneller als C++. Selbst die Variante slow_convex_hull() 
mit push() und pop() ist etwa gleich schnell wie die C++ Version: C++ 
und Nim slow_convex_hull etwa 0.28s und Nim convex_hull etwa 0.25s. 
Jeweils compiliert mit gcc/g++ 4.8.3 mit -O3. Etwas langsamer wird alles 
mit der Initialisierung durch "v = map(...". aber das ist ja irrelevant. 
Fazit: Ich hätte doch gedacht, dass pop() und push() etwas mehr Zeit 
frisst. Und dass Nim in diesem Beispiel gleichauf mit C++ liegt ist doch 
etwas mehr, als ich erwartet hatte. Bei den Dateigrößen sieht es für Nim 
nicht ganz so gut aus, da ist wohl doch stets einges vom Laufzeitsystem 
enthalten, insbesondere der GC.
1
ls -lt a.out convex_hull
2
15320 Nov 13 21:14 a.out (g++ -O3)
3
84936 Nov 13 21:12 convex_hull (nim c -d:release)
Hier der C++ und Nim-Code:
1
#include <algorithm>
2
#include <vector>
3
#include <iostream>
4
using namespace std;
5
typedef double coord_t;
6
typedef double coord2_t;
7
 
8
struct Point {
9
  coord_t x, y;
10
  bool operator <(const Point &p) const {
11
    return x < p.x || (x == p.x && y < p.y);
12
  }
13
};
14
 
15
coord2_t cross(const Point &O, const Point &A, const Point &B)
16
{
17
  return (A.x - O.x) * (B.y - O.y) - (A.y - O.y) * (B.x - O.x);
18
}
19
 
20
vector<Point> convex_hull(vector<Point> P)
21
{
22
  int n = P.size(), k = 0;
23
  vector<Point> H(2*n);
24
  sort(P.begin(), P.end());
25
  for (int i = 0; i < n; ++i) {
26
    while (k >= 2 && cross(H[k-2], H[k-1], P[i]) <= 0) k--;
27
    H[k++] = P[i];
28
  }
29
  for (int i = n-2, t = k+1; i >= 0; i--) {
30
    while (k >= t && cross(H[k-2], H[k-1], P[i]) <= 0) k--;
31
    H[k++] = P[i];
32
  }
33
  H.resize(k);
34
  return H;
35
}
36

37
#define Max 1000
38
#define NumPoints (Max * Max)
39

40
using namespace std;
41
int main()
42
{
43
  vector<Point> v(NumPoints);
44
  int i;
45
  for (i = 0; i < NumPoints; i++)
46
  {
47
    v[i].x =  i / Max; 
48
    v[i].y =  i % Max;
49
    //cout << v[i].x <<v[i].y << endl;
50
  }
51
  cout << endl;
52
  
53
  vector<Point> h = convex_hull(v);
54
  int s = h.size();
55
  for (i = 0; i < s; i++)
56
  {
57
    cout << "(" << h[i].x << "," << h[i].y << ") ";
58
  }
59
  cout << endl;
60
}
1
import algorithm, sequtils
2
const
3
  Max = 1000
4
  NumPoints = Max * Max
5

6
type Point = tuple[x, y: float]
7

8
proc cmpPoint(a, b: Point): int =
9
  result = cmp(a.x, b.x)
10
  if result == 0:
11
    result = cmp(a.y, b.y)
12

13
template cross[T](o, a, b: T): expr =
14
  (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x)
15

16
proc slower_convex_hull[T](points: var seq[T], cmp: proc(x, y: T): int {.closure.}) : seq[T] =
17
  points.sort(cmp)
18
  var lower: seq[T] = @[]
19
  for p in points:
20
    while len(lower) > 1 and cross(lower[len(lower) - 2], lower[len(lower) - 1], p) <= 0:
21
      discard lower.pop
22
    lower.add(p)
23
  var upper: seq[T] = @[]
24
  for i in countdown(high(points), low(points)):
25
    let p = points[i]
26
    while len(upper) > 1 and cross(upper[len(upper) - 2], upper[len(upper) - 1], p) <= 0:
27
      discard upper.pop
28
    upper.add(p)
29
  result = concat(lower[0 .. -2], upper[0 .. -2])
30

31
proc convex_hull[T](points: var seq[T], cmp: proc(x, y: T): int {.closure.}) : seq[T] =
32
  points.sort(cmp)
33
  let n = points.len
34
  var k = 0
35
  result = newSeq[T](2 * n)
36
  for p in points:
37
    while k > 1 and cross(result[k-2], result[k-1], p) <= 0:
38
      dec(k)
39
    result[k] = p
40
    inc(k)
41
  var
42
    i = n - 2
43
    t = k + 1
44
  while i >= 0:
45
    while k >= t and cross(result[k-2], result[k-1], points[i]) <= 0:
46
      dec(k)
47
    result[k] = points[i]
48
    inc(k)
49
    dec(i)
50
  result.setLen(k-1)
51

52
#var v = map(toSeq(0..<MaxPoints), proc(x: int): Point = (float(x div Max), float(x mod Max)))
53

54
var
55
  v = newSeq[Point](NumPoints)
56
  i = 0
57

58
while i < NumPoints:
59
  v[i].x =  (float) (i div Max) 
60
  v[i].y =  (float) (i mod Max)
61
  inc(i)
62
  
63
#echo slower_convex_hull[Point](v, cmpPoint)
64
echo convex_hull[Point](v, cmpPoint)
65

66
#assert(convex_hull[Point](s, cmpPoint) == @[(0.0, 0.0), (999.0, 0.0), (999.0, 999.0), (0.0, 999.0)])

Übrigens frage ich mich, wieso mit
1
   vector<Point> H(2*n);
in dem Wikibook C++ Code ein Vektor doppelt so groß wie der 
Ursprüngliche angelegt wird? Die Hülle kann doch eigentlich nie mehr 
Punkte als die ursprüngliche Punkmenge haben? Na gut, der erste und 
letzte Punkt werden ja zunächt doppelt gespeichert, aber da sollte ja 
irgendwas wie +1 reichen?

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 11 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.