2009-01-26 16 views
6

Tôi có một lớp đại diện cho một hình dạng. Lớp Shape có một thuộc tính được gọi là Angle. Tôi muốn setter cho thuộc tính này tự động quấn giá trị vào trong phạm vi [0,359].Trong C#, làm cách nào để thực hiện mô đun như google calc?

Thật không may, một đơn giản _Angle = value % 360; chỉ hoạt động với số dương. Trong C#, -40 % 360 == -40. Google calc làm điều đó the way I want it. Giá trị phải là 320.

Giải pháp thanh lịch nhất trong C# là gì?

Đây là cách tốt nhất mà tôi đã có cho đến nay:

 public double Angle { 
     get { return _Angle; } 
     set { 
      if (value >= 0) { 
       _Angle = value % 360; 
      } 
      else { 
       _Angle = value - (360 * ((int)(value/360) - 1)); 
      } 
     } 
    } 

Edit:

Thanks guys, bây giờ tôi có:

 public double Angle { 
     get { return _Angle; } 
     set { 
      _Angle = (value % 360) + ((value < 0) ? 360 : 0); 
     } 
    } 

đồi khế, đồi là rất nhiều tốt hơn :)

+1

Tôi sẽ mạnh mẽ không khuyến khích sử dụng thao tác mod vì mod/phân vùng phần cứng chậm. Nếu bạn có thể mở rộng dữ liệu của bạn thành một sức mạnh của hai, bạn có thể sử dụng một giải pháp tốt hơn để tận dụng các mặt nạ bit. –

+0

@TrevorBoydSmith: Trình biên dịch C# có được phép tối ưu hóa phép chia và mô đun thành bit trong trường hợp các số nguyên không? Bạn có thể tối ưu hóa hoạt động bit trong trường hợp các giá trị thả nổi không? –

Trả lời

9

Mặc dù điều này là dành cho Java, Java cũng có cùng hành vi đối với mô đun. (ví dụ: -40 % 360 == -40).

Mã bên dưới sẽ trả về câu trả lời từ [0. 360), bất kể góc đã cho, dương hay âm.

public class Mod 
{ 
    public static int mod(int a, int b) 
    { 
     if (a < 0) 
      return b + (a % b); 
     else 
      return a % b; 
    } 

    public static void main(String[] args) 
    { 
     System.out.println(mod(40, 360)); // 40 
     System.out.println(mod(-40, 360)); // 320 
     System.out.println(mod(-400, 360)); // 320 
    } 
} 

Lưu ý rằng hoạt động khi góc đã cho là quá -360.

+0

wow đây là cách quá phức tạp, bạn thực sự không cần thêm nếu tuyên bố. –

+0

Hah, tất nhiên rồi! Đơn giản hơn nhiều so với mã của tôi. – Blorgbeard

1

// go 'round once

set { _Angle = (value + 360) % 360 }

+0

Tôi nghĩ về điều đó, nhưng nếu một giá trị nhỏ hơn -360 được thông qua thì sao? – Blorgbeard

+0

Có, tôi giả định ở đây rằng Góc được chuẩn hóa ở mọi bản cập nhật. –

-1
(360 * Math.floor(Math.abs(value)/360) + value) % 360 
-1

Nếu giá trị của bạn sẽ không vượt quá phạm vi, bạn có thể thực hiện một vòng lặp nhỏ.

while (value < 0) { 
    value = value + 360; 
} 
while (value > 360) { 
    value = value - 360; 
} 
3

Điều này sẽ cho bạn những kết quả cần

public double Angle { 
    get { return _Angle; } 
    set { _Angle = value % 360 + (value % 360 < 0 : 360 : 0); } 
} 

Tôi giả định rằng 360 là độ và bạn đang cố gắng tìm nơi trong {0, 360} góc nằm.

+1

(-1) bạn có thể sử dụng coobird nếu không cần thiết nếu mã của bạn được sử dụng không đúng?:. Bạn có nghĩ rằng trình biên dịch không tạo ra một điều kiện cho điều này? – RAL

+1

Vâng (-1) lại với bạn, nó không phải là cách ông đã sử dụng câu lệnh IF, đó là một thực tế ông đã không đáp ứng những gì các poster yêu cầu. ông đã có một tuyên bố IF, tác giả muốn giảm thiểu mã của mình, thêm một phương pháp khác với một câu lệnh IF trong nó không làm điều đó –

+1

Bạn thực sự có thêm '%' ở đây nữa - 'giá trị% 360' nhỏ hơn 0 iff 'giá trị' nhỏ hơn 0. – Blorgbeard

4

Trong khi giải pháp của bạn hoạt động cho sự cố bạn có thuật toán thực sự không giống với giải pháp được Google sử dụng. Nó khác nếu bạn sử dụng ước số âm.

public double GoogleModulo(double value, double divisor) 
{ 
    long q = (long)Math.Floor(value/divisor); 
    return value - q * divisor; 
} 

Console.WriteLine(GoogleModulo( 40, 360)); // 40 
Console.WriteLine(GoogleModulo(-40, 360)); // 320 
Console.WriteLine(GoogleModulo(-400, 360)); // 320 
Console.WriteLine(GoogleModulo( 40, -360)); // -320 

Kiểm tra phản hồi của google về phép tính cuối cùng here.

Thuật toán được giải thích trên wikipedia và được gán cho Donald Knuth.

2

Thao tác mod rất chậm. Nếu có thể thay bằng mặt nạ bit.

mã của coobird khá tốt ... nhưng rất chậm vì nó đang thực hiện thao tác mod. Nếu có thể mở rộng dữ liệu của bạn trong phạm vi một số sức mạnh của hai phạm vi, sau đó bạn có thể cải thiện tốc độ bằng khoảng một bậc độ lớn (ít nhất là 2 hoặc 3 lần nhanh hơn) bằng cách sử dụng một mặt nạ bit.

mã C:

#define BIT_MASK (0xFFFF) 
if (a < 0) { 
    return b + (a & BIT_MASK); 
} else { 
    return a & BIT_MASK; 
} 

Hãy thoải mái để làm cho một cái gì đó #define được chạy thời gian. Và cảm thấy tự do để điều chỉnh mặt nạ bit để được bất cứ sức mạnh của hai mà bạn cần. Giống như 0xFFFFFFFF hoặc sức mạnh của hai bạn quyết định thực hiện.

+0

Trừ khi các thiết lập của góc là lấy một lượng lớn thời gian CPU tôi nghĩ là không có giá trị nỗ lực. Máy tính hiện tại của tôi có thể thực hiện các hoạt động mô-đun 450 millons cho các góc nhỏ sử dụng 2 luồng. Sử dụng Bit hoạt động nhanh gấp 2,5-3 lần. Trong hoạt động 1 millon, nó chỉ tiết kiệm được 1,5 mili giây. – ggf31416

+0

Nếu 2 đến 3 x hiệu suất tăng không phải là 'tốt', vấn đề của bạn có vẻ như bạn đang thực hiện tối ưu hóa sớm trên một số thứ nhỏ (ví dụ: số gói) khi bạn nên tập trung vào các vấn đề lớn hơn. Rất nhiều thứ tôi làm việc có thời hạn thực sự khó khăn và phải thực hiện trong vài giây. –

+0

tối ưu hóa tốt đẹp Trevor –

Các vấn đề liên quan