2010-02-17 16 views
6

Tôi muốn giảm giá trị một và nếu giá trị đó bằng 0, đặt giá trị đó thành giá trị lớn nhất. Có cách nào để thực hiện việc này thông qua toán học mà không cần phải if (n-1 == 0) { n = max; }Có cách nào để thực hiện logic boolean rất đơn giản này chỉ sử dụng toán hạng toán học (chẳng hạn như mod)?

Kịch bản ngược lại để tăng giá trị một và sau đó đặt thành 0 khi lớn hơn cực đại có thể dễ dàng đạt được bằng cách sử dụng n = (n + 1) % (max + 1);. Hơn nữa, điều này thậm chí còn tốt hơn vì bạn có thể tăng thêm bất kỳ số tiền nào (không chỉ một) và nó sẽ vẫn "bọc" một cách chính xác.

Cảm ơn câu trả lời cho đến thời điểm này. Để được rõ ràng, tôi có nghĩa là không có bất kỳ logic boolean (if/else) hoặc boolean nhà khai thác (!, & &, vv) ở tất cả. Tôi chỉ tò mò làm thế nào để làm điều này. Câu trả lời đúng dưới đây có thực sự khiến câu trả lời không đọc được miễn là nhận xét được cung cấp không? Nó sẽ là cần thiết để sử dụng cho trường hợp tổng quát hơn để trừ một số tùy ý và mong đợi quấn đúng xung quanh.

+0

Ozan đặt câu hỏi hay dưới đây. Ngoài sự tò mò, đây có phải là một câu đố logic hay không, có lý do nào đó mà ai đó cần phải tránh các cấu trúc ngôn ngữ cơ bản không? – MightyE

+0

Xem ở trên. Sử dụng nếu như thế chỉ hoạt động nếu bạn trừ một, và không nếu bạn đang trừ một số tùy ý và mong đợi cùng một loại bọc xung quanh như mod cung cấp. – GreenieMeanie

Trả lời

6
n = max - ((max - n +1)%max) 
+7

Điều đó trả lời cho câu hỏi và đặt ra một câu hỏi mới: tại sao một người sẽ thay thế một câu lệnh đơn giản bằng một câu lệnh phức tạp làm điều tương tự? – Ozan

1

Vấn đề là nhà điều hành % trong C trả về kết quả âm khi đối mặt với cổ tức âm. Đây không phải là điều cần thiết.

Nếu bạn muốn có một chức năng mod để thỏa mãn các -1 mod n == n-1, sau đó, trong C, bạn phải làm như sau:

int mod(int a, int b) 
{ 
    return (a%b + b) % b; 
} 

Sau đó bạn có thể làm

n=mod(n-1, max+1); 

để giảm giá trị n và có nó quấn quanh max khi n==0. Lưu ý rằng, đối với trường hợp gia tăng, điều này sẽ làm việc cho các kích thước bước tùy ý.

+1

Điều này thực sự tồi tệ hơn: toán tử '%' trong C có thể trả về kết quả dương hoặc âm * khi kết quả là số âm. Tất cả những gì cần thiết là bạn có thể đặt các kết quả từ '/' và '%' lại với nhau thành số ban đầu. –

+0

@Jerry: Điều đó đúng theo C89.Tuy nhiên, tiêu chuẩn C hiện tại yêu cầu phân chia số nguyên cắt ngắn về 0. Cùng với yêu cầu bạn đề cập, điều này hoàn toàn xác định toán tử '%'. –

1

Có đủ biến thể về toán học giữa các ngôn ngữ mà tôi nghi ngờ có một cách không thuyết phục về ngôn ngữ để thực hiện việc này. Chỉ đơn giản là có quá nhiều biến thể trong cách ngôn ngữ viết biểu thức cho một kỹ thuật đơn cơ bản để làm việc với mọi ngôn ngữ có thể.

Nếu bạn chọn một ngôn ngữ cụ thể, có khả năng rất tốt là có thể. Ví dụ: trong C hoặc C++, bạn có thể làm điều gì đó như: n = (n-1) + ((n-1) == 0) * max;

Trường hợp bạn quan tâm đến cách hoạt động: trong C, so sánh (== trong trường hợp này) tạo kết quả là 0 và false . Vì vậy, những gì chúng tôi đang làm là thêm max * 0 khi/nếu n-1 != 0max * 1 khi/nếu n-1 == 0.

-1

Tại sao không chỉ so sánh với 1?

if(n==1) { n = max; }

+0

Những gì tôi hỏi trong câu hỏi là một thay thế để so sánh nó như bạn. – GreenieMeanie

5

Nếu bạn đang làm điều này hoàn toàn vì lý do hiệu suất sau đó tôi sẽ tư vấn cho chống lại nó. % thường là một hoạt động khá tốn kém trên hầu hết các kiến ​​trúc - một so sánh đơn giản, chi nhánh và bổ sung thường sẽ hiệu quả hơn. Tất nhiên các thông báo trước về việc tối ưu hóa đầu cơ/sớm được áp dụng.

+3

Và thông báo trước rằng kiến ​​trúc thay đổi khá một chút, và thay đổi khá nhanh và không theo những cách có thể đoán trước được. Tôi đã từ bỏ cố gắng đoán thứ hai, ngoại trừ vị trí bộ nhớ cache. –

+1

Tôi đã thử biên dịch (với tối ưu hóa đầy đủ) và tháo rời, và có vẻ như bạn đang đúng: không chỉ là cách ban đầu ngắn hơn, nó có ít nhánh hơn (!). Tôi đoán trong phần cứng bạn cần phải làm một bộ phận để có được modulo, và phân chia không phải là giá rẻ hoặc dễ dàng. – Ken

0

Có thể có cách tốt hơn nhưng tôi nghĩ rằng n = max - (max - n + 1) % (max + 1) hoạt động. Tôi giả sử bạn muốn bao gồm 0 ở cả hai đầu vì biểu thức tăng của bạn mà bạn bao gồm 0.

-1

Trong bất kỳ ngắn mạch ngôn ngữ đánh giá logic (hầu hết các ngôn ngữ hiện đại), bạn có thể làm một cái gì đó như thế này:

--n<=0 && n=max;

Bạn có thể nhận nhãn cầu lông từ một số đồng nghiệp của bạn nếu nhóm của bạn không phải là đã quen với việc sử dụng & & làm toán tử if-then.

Để thực hiện điều chuyển tiếp lặp increment:

++n>max && n=1;

Những ví dụ này giả định một bộ đếm 1-lập chỉ mục từ câu hỏi của bạn dường như để giả định rằng. 0-lập chỉ mục tương đương là:

--n<0 && n=max-1;

++n>=max && n=0;

+0

--n sẽ không hoạt động đối với một loại không dấu có lẽ là lý do anh tránh so sánh. – Joel

+0

Nó sẽ vẫn hoạt động đối với trường hợp được lập chỉ mục một. Đối với trường hợp chưa được đánh chỉ mục không được lập chỉ mục, điều này sẽ hoạt động nếu ngôn ngữ không có lỗi trên dòng nguyên nguyên: 'n - == 0 && n = max-1'. Bạn nói đúng, OP là ngôn ngữ bất khả tri, vì vậy tôi chỉ giả định int (trường hợp của tôi cũng sẽ phá vỡ nếu bạn sử dụng phao, vv). – MightyE

0

Trên thực tế bạn có thể làm cũng

n = (n - 1) + ((!(n - 1)) * max); 
0

Làm thế nào về vấn đề này:
n = n * max + (!! n) * n;

0

Re: không có dữ liệu boolean
Vâng, thông qua sự kỳ diệu của phép chia số nguyên (C-style), câu trả lời trước của tôi có thể được viết như sau:
n = ((max-n)/max) * max + ((max + n-1)/max) * n;

0

Chỉ cần hỏi: tại sao bạn muốn tránh hoạt động boolean?

Nếu bạn muốn tránh mã có điều kiện trong ứng dụng của mình, bạn có thể sử dụng các biểu thức boolean được lưu trữ trong các giá trị boolean. Chúng sẽ được ánh xạ tới các lệnh SETcc trên một i386 và tôi giả thiết rằng các phiên bản tương tự tồn tại trên các ISA khác.

Trong trường hợp đó bạn có thể sử dụng một biểu thức boolean và vẫn có mã không có điều kiện và bạn có thể sử dụng:

Theo giả định rằng một kết quả boolean true bằng với thứ tự 1 (đây là trường hợp trong mã Delphi) và giá trị boolean của false bằng 0 bạn có thể viết

next := current - 1 + ((1 + max) and -Ord(current = 0)); 

Đừng bỏ phiếu này xuống vì tôi đã trả lời với các thao tác boolean. Tôi chỉ muốn kiểm tra xem đây có phải là giải pháp differnet cho vấn đề cơ bản hay không.

Vẫn: Tôi cho rằng mã có điều kiện dễ đọc hơn nhiều.

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