2012-03-15 62 views
6

Tôi cần xác định góc phần tư của điểm, theo cách nhanh hơn. Tôi chỉ biết phương pháp "xác định sử dụng dấu hiệu". Tôi đang tìm một cách tiếp cận tốt, nếu có. Nếu không có bất kỳ bản sửa lỗi nào cho mã của tôi sẽ hữu ích. Giả sử có 4 quad trên mặt phẳng. Mã của tôi-Xác định góc phần tư của một điểm

 int x = scan.nextInt() > 0 ? 1 : 0; 
     int y = scan.nextInt() > 0 ? 1 : 0; 
     switch (x) { 
     case 1: 
      switch (y) { 
      case 1: 
       quad = 1; 
       break; 
      case 0: 
       quad = 4; 
       break; 
      } 
      break; 

     case 0: 
      switch (y) { 
      case 1: 
       quad = 2; 
       break; 
      case 0: 
       quad = 3; 
       break; 
      } 
      break; 
     } 
+0

Đây có phải là bài tập về nhà không? Bạn đã triển khai thuật toán "xác định sử dụng dấu hiệu" chưa? Có một vấn đề hiệu suất với nó (tại sao nó không đủ nhanh?). Cho chúng tôi xem mã của bạn. – Jesper

+0

@Jesper Không phải bài tập về nhà. Đã dán mã của tôi. – sgowd

+0

Ok, vậy tại sao nó không đủ nhanh? – Jesper

Trả lời

4

nhánh và bộ nhớ nhìn ups là những điều cần tránh khi thực hiện tối ưu hóa vi trên một đoạn mã. Với việc lắp ráp nội tuyến, bạn có thể sử dụng CMOV (MOV có điều kiện) để tăng tốc trên các hệ thống x86. Trình biên dịch hotspot của Java cũng có thể được sử dụng trong hướng dẫn này. Nhưng vì đoạn mã đơn giản như vậy, nên thực hiện quá nhiều thao tác để tránh việc phân nhánh hoặc tìm kiếm bộ nhớ có thể (cuối cùng) là kẻ đánh bại.

static int[] QUAD_LUT = new int[]{1, 2, 4, 3}; 
... 
// use the sign bit on the integers 
return QUAD_LUT[ (x >> 31) | ((y >> 30) & 0x2) ] 

Khi bạn nghĩ về kết quả sau khi bạn

x.sign y.sign Quad 
0  0  1 
0  1  4 
1  0  2 
1  1  3 

Bạn có thể nhận được công thức

(x.sign XOR y.sign + y.sign + y.sign) + 1 

Vì vậy, trong Java

y = y>>31; 
return ((x>>31)^y) + y + y + 1; 

EDIT Chỉ cần cho những người tò mò về lắp ráp nội tuyến ...

;; NASM/FASM syntax 
;; GetQuadrant(int x, int y) 
;; RETURN [1|2|3|4] in EAX register 
GetQuadrant: 
    MOV  eax, [esp+4] ;; = x 
    MOV  ecx, [esp+8] ;; = y 
    SHR  eax, 31 ;; = >> 31 
    SHR  ecx, 31 ;; = >> 31 
    XOR  eax, ecx ;; = x XOR y 
    LEA  eax, [eax + ecx * 2 + 1] ;; = x + y*2 + 1 
    RET  8 ;; correct stack and return 
+0

Rất đẹp, xin chúc mừng! – PhyBandit

+0

Đẹp nhất. Tôi không hiểu ý tưởng của những nhà khai thác này. – sgowd

4

Đây là phương pháp dành cho bạn. Có vẻ đơn giản ...

getQuadrant(int x, int y) { 
    if (x >= 0) { 
     return y >= 0 ? 1 : 4; 
    } else { 
     return y >= 0 ? 2 : 3; 
    } 
} 
+0

Nó thực sự là một trong những đơn giản hơn tôi. Nhưng không nhanh hơn. – sgowd

+0

Nếu mục tiêu là hiệu suất, câu trả lời này không chính xác. Nhánh là một trở ngại hiệu suất được biết đến. Nếu mục tiêu là thực tế/rõ ràng nhất thì đây là một chiến thắng rõ ràng. –

1
int[] quads = new int[] { 3, 2, 4, 1 }; 

int x = scan.nextInt() > 0 ? 2 : 0; 
int y = scan.nextInt() > 0 ? 1 : 0; 

int result = quads[x + y]; 
+0

Hiệu suất khôn ngoan này đang sử dụng 2 nhánh và bộ nhớ tìm kiếm. Sử dụng một phiên bản chi nhánh ít hơn với một "quads" tĩnh nhìn lên có lẽ sẽ làm cho nó trở thành sự lựa chọn chung cho tối ưu hóa. –

0

Giữ nó đơn giản! Không cần các chi nhánh, bit-twiddling, tra cứu bộ nhớ, ngôn ngữ lắp ráp, hoặc các biến chứng khác. .

int getQuadrant(int x, int y) { 
    int X = (x >= 0); 
    int Y = (y >= 0); 
    return 3 + X - Y - 2 * X * Y; 
} 

(Giải thích Với XY như trong chức năng của tôi, góc phần tư được đưa ra bởi đa thức bậc hai này:

1 * X * Y + 2 * (1 - X) * Y + 3 * (1 - X) * (1 - Y) + 4 * X * (1 - Y) 

và sau đó nếu bạn thu thập các điều khoản và đơn giản hóa, bạn sẽ có được sự biểu hiện Tôi đã sử dụng.)

+0

Đây không phải là JAVA. Tôi không thể khởi tạo int X = (x> = 0); Vì biểu thức trả về một Boolean. – sgowd

+0

Ah, tốt. Tôi nghĩ rằng loại điều này thể hiện lợi thế của [quy ước Iverson] (http://en.wikipedia.org/wiki/Iverson_bracket) qua một loại boolean riêng biệt. –

0

Tôi thực sự thích ví dụ bit xoắn ở trên - nhưng tôi cần điều này trong 3d và trong C ... vì vậy chỉ trong trường hợp điều này là hữu ích. Tôi chắc rằng điều này là đủ gần để chuyển đổi sang java anyway nếu ai đó cần nó.

int 
point_to_3d_quad (int x, int y, int z) 
{ 
    static int q[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; 

    int X = (x >> ((sizeof(x)*8)-1)) & 1; 
    int Y = ((y >> ((sizeof(y)*8)-1)) & 1) << 1; 
    int Z = ((z >> ((sizeof(z)*8)-1)) & 1) << 2; 

    return (q[X | Y | Z]); 
} 
Các vấn đề liên quan