Forum: PC-Programmierung Ergänzung zu Yalus Tests


von Stefan (Gast)


Lesenswert?

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?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.