Con số này có phải là sức mạnh chính xác của -2: (Rất) Chế độ cứng


26

Đây là một phiên bản của thử thách gần đây Con số này có phải là số nguyên của -2 không? với một bộ tiêu chí khác nhau được thiết kế để làm nổi bật bản chất thú vị của vấn đề và làm cho thách thức trở nên khó khăn hơn. Tôi xem xét một số ở đây .

Thách thức như Toby đã nêu một cách tuyệt vời trong câu hỏi được liên kết, là:

Có nhiều cách thông minh để xác định xem một số nguyên có phải là công suất chính xác không 2. Đó không còn là vấn đề thú vị nữa, vì vậy hãy xác định xem một số nguyên đã cho có phải là công suất chính xác của -2 hay không . Ví dụ:

-2 => yes: (-2)¹
-1 => no
0 => no
1 => yes: (-2)⁰
2 => no
3 => no
4 => yes: (-2)²

Quy tắc:

  • Một số nguyên là 64 bit, đã ký, hai phần bù. Đây là loại dữ liệu duy nhất bạn có thể làm việc với.
  • Bạn chỉ có thể sử dụng các hoạt động sau đây. Mỗi trong số này được tính là một hoạt động.
    • n << k, n >> k: Dịch chuyển trái / phải ntheo kbit. Dấu bit được mở rộng trong ca phải.
    • n >>> k: Phải dịch chuyển nhưng không mở rộng bit dấu. 0 là được chuyển trong.
    • a & b, a | b, a ^ b: Bitwise AND, OR, XOR.
    • a + b, a - b, a * b: Thêm cộng, trừ, nhân.
    • ~b: Đảo ngược bit.
    • -b: Hai phủ định bổ sung.
    • a / b, a % b: Chia (thương số nguyên, làm tròn về 0) và modulo.
      • Modulo của số âm sử dụng các quy tắc được chỉ định trong C99 : (a/b) * b + a%bsẽ bằng nhau a. Vì vậy, 5 % -32, và -5 % 3-2:
      • 5 / 31, 5 % 32, như 1 * 3 + 2 = 5.
      • -5 / 3-1, -5 % 3-2, như -1 * 3 + -2 = -5.
      • 5 / -3-1, 5 % -32, như -1 * -3 + 2 = 5.
      • -5 / -31, -5 % -3-2, như 1 * -3 + -2 = -5.
      • Lưu ý rằng //toán tử phân chia tầng của Python không thỏa mãn tính chất phân chia "tròn về 0" ở đây và %toán tử của Python cũng không đáp ứng các yêu cầu.
    • Bài tập không được tính là một hoạt động. Như trong C, các phép gán đánh giá giá trị của phía bên trái sau khi gán: a = (b = a + 5)đặt bthành a + 5, sau đó đặt athành bvà được tính là một thao tác.
    • Bài tập tổng hợp có thể được sử dụng a += bphương tiện a = a + bvà được tính là một thao tác.
  • Bạn có thể sử dụng hằng số nguyên, chúng không được tính là bất cứ thứ gì.
  • Dấu ngoặc đơn để xác định thứ tự các hoạt động được chấp nhận.
  • Bạn có thể khai báo các chức năng. Khai báo hàm có thể theo bất kỳ kiểu nào thuận tiện cho bạn nhưng lưu ý rằng số nguyên 64 bit là kiểu dữ liệu hợp lệ duy nhất . Khai báo hàm không được tính là hoạt động, nhưng một lệnh gọi hàm được tính là một. Ngoài ra, để rõ ràng: Các hàm có thể chứa nhiều returncâu lệnh và returns từ bất kỳ điểm nào được cho phép. Bản returnthân nó không được tính là một hoạt động.
  • Bạn có thể khai báo các biến miễn phí.
  • Bạn có thể sử dụng whilecác vòng lặp, nhưng bạn không thể sử dụng ifhoặc for. Toán tử được sử dụng trong whileđiều kiện tính vào điểm số của bạn. whilecác vòng lặp thực thi miễn là điều kiện của chúng ước tính giá trị khác không ("trung thực" 0 trong các ngôn ngữ có khái niệm này không phải là kết quả hợp lệ). Kể từ sớm trở lại được cho phép, bạn được phép sử dụng breakcũng
  • Tràn / tràn được cho phép và không có giá trị kẹp sẽ được thực hiện. Nó được xử lý như thể hoạt động thực sự xảy ra chính xác và sau đó bị cắt thành 64 bit.

Tiêu chí chấm điểm / chiến thắng:

Mã của bạn phải tạo ra một giá trị khác không nếu đầu vào là lũy thừa -2 và khác 0.

Đây là . Điểm của bạn là tổng số thao tác có trong mã của bạn (như được xác định ở trên), không phải là tổng số thao tác được thực hiện trong thời gian chạy. Các mã sau đây:

function example (a, b) {
    return a + ~b;
}

function ispowerofnegtwo (input) {
    y = example(input, 9);
    y = example(y, 42);
    y = example(y, 98);
    return y;
}

Chứa 5 hoạt động: hai trong chức năng và ba cuộc gọi chức năng.

Không quan trọng bạn trình bày kết quả của mình như thế nào, sử dụng bất cứ điều gì thuận tiện trong ngôn ngữ của bạn, cuối cùng là lưu trữ kết quả trong một biến, trả về từ một hàm hoặc bất cứ điều gì.

Người chiến thắng là bài đăng chính xác (cung cấp bằng chứng ngẫu nhiên hoặc chính thức nếu cần thiết) và có số điểm thấp nhất như mô tả ở trên.

Thưởng thử thách chế độ rất khó!

Để có cơ hội chiến thắng hoàn toàn không có gì ngoại trừ khả năng gây ấn tượng với mọi người trong các bữa tiệc, hãy gửi câu trả lời mà không cần sử dụng whilecác vòng lặp! Nếu đủ số này được gửi, tôi thậm chí có thể xem xét chia các nhóm chiến thắng thành hai loại (có và không có vòng lặp).


Lưu ý: Nếu bạn muốn cung cấp giải pháp bằng ngôn ngữ chỉ hỗ trợ số nguyên 32 bit, bạn có thể làm như vậy, miễn là bạn đủ khả năng biện minh rằng nó sẽ vẫn đúng cho số nguyên 64 bit trong phần giải thích.

Ngoài ra: Một số tính năng cụ thể về ngôn ngữ có thể được cho phép miễn phí nếu chúng không trốn tránh các quy tắc nhưng cần thiết để ép buộc ngôn ngữ của bạn hành xử theo các quy tắc trên . Ví dụ (giả định), tôi sẽ cho phép miễn phí không bằng 0 so với whilecác vòng lặp, khi áp dụng cho điều kiện nói chung, như một cách giải quyết cho một ngôn ngữ có "0" trung thực. Các nỗ lực rõ ràng để tận dụng các loại điều này là không được phép - ví dụ: khái niệm giá trị "trung thực" 0 hoặc "không xác định" không tồn tại trong quy tắc trên và do đó chúng có thể không được dựa vào.


Bình luận không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện .
Dennis

@hvd Nếu bạn đọc điều này: Bạn nên hoàn toàn xóa bỏ câu trả lời của bạn! Giả sử nó là chính xác, ngay cả khi m ^= s nó vẫn không ấn tượng và tôi nghĩ sẽ hoàn toàn ổn khi thay thế để cải thiện nó nhiều hơn nữa.
Jason C

Làm thế nào nó có ý nghĩa để cho phép whilebreakkhông if? if (x) { ... }tương đương với while (x) { ... break; }.
R ..

@R .. Nó không có ý nghĩa 100% ( breakvà lợi nhuận sớm là phần đáng tiếc) và là một câu chuyện dài và một bài học kinh nghiệm về các quy tắc cho các thách thức trong tương lai. Luôn có phiên bản "tiền thưởng"! :)
Jason C

1
Tại sao ifforkhông được phép? int x=condition; while (x) { ... x=0; }là miễn phí, chỉ cần thêm mã. Điều tương tự với phong cách c for.
Qwertiy

Câu trả lời:


35

C ++, 15 thao tác

Tôi không biết tại sao whilecác vòng lặp được cho phép khi chúng phá hủy toàn bộ thử thách. Đây là một câu trả lời mà không có bất kỳ:

int64_t is_negpow2(int64_t n) {
    int64_t neg = uint64_t(n) >> 63; // n >>> 63
    n = (n ^ -neg) + neg; // if (n < 0) n = -n;
    int64_t evenbits = n & int64_t(0xaaaaaaaaaaaaaaaaull >> neg);
    int64_t n1 = n - 1;
    int64_t pot = n & n1;
    int64_t r = pot | (n1 >> 63) | evenbits;
    return ~((r | -r) >> 63); // !r
}

Tại sao whilecác vòng lặp phá hủy toàn bộ thách thức ?
Ông Xcoder

10
@ Mr.Xcoder Bởi vì thách thức là thực hiện nó với các thao tác bitwise đơn giản và whileđi ngược lại điều đó theo mọi cách.
orlp

Ý tôi là, trừ khi bạn thực hiện các vòng lặp while nhân số lần thao tác nhân với số lần thực hiện trong vòng lặp cho một tĩnh nhoặc một cái gì đó.
Bạch tuộc ma thuật Urn

Tôi đã bình luận về điều này ở đây .
Jason C

@JasonC Đó là vì tôi nên sử dụng một ca làm việc đúng mà không cần bit dấu. Tôi đã chỉnh sửa mã (nó sử dụng uint64_tvì đó là cách duy nhất để có được sự thay đổi đúng mà không cần gia hạn ký hiệu.)
orlp

25

Thao tác Python 2 , 3

def f(n):
 while n>>1:
  while n&1:return 0
  n=n/-2
 return n

Hãy thử trực tuyến!

Các hoạt động được >>, &, /.

Ý tưởng là liên tục chia cho -2. Quyền hạn của chuỗi -2 xuống còn 1 : -8 -> 4 -> -2 -> 1. Nếu chúng ta đánh a 1, chấp nhận. Nếu chúng ta đánh một số lẻ trước khi đánh 1, hãy từ chối. Chúng ta cũng cần phải từ chối 0, mà mãi mãi đi đến chính nó.

Các while n>>1:vòng lặp cho đến n0 hoặc 1. Khi vòng lặp bị phá vỡ, nchính nó được trả về và 1là đầu ra Truthy và 0Falsey. Trong vòng lặp, chúng tôi từ chối áp dụng nhiều lần n -> n/-2và từ chối bất kỳ số lẻ nào n.

/chỉ được sử dụng trên các giá trị chẵn, nên hành vi làm tròn của nó không bao giờ phát huy tác dụng. Vì vậy, không có vấn đề gì khi Python làm tròn khác với thông số kỹ thuật.


Tốt đẹp. Logic thông minh trong thuật toán và công việc tốt kết hợp các điều kiện vào các hoạt động bit. Ngoài ra, có thể xác nhận, việc triển khai hoạt động trong C.
Jason C

Tại sao while n&1thay vì if n&1?
Mark Ransom

2
@MarkRansom Thử thách không cho phép if.
xnor

Aha, đã bỏ lỡ điều đó. Thay thế rất thông minh.
Đánh dấu tiền chuộc

1
@EvSunWoodard Điểm số là số lượng toán tử trong mã, không phải số lượng cuộc gọi đến chúng trong khi thực hiện, điều này phụ thuộc vào đầu vào: "Đây là golf-code-nguyên tử. Điểm của bạn là tổng số thao tác có trong mã của bạn . "
xnor

11

Rỉ 14 12 thao tác (không có vòng lặp)

Yêu cầu tối ưu hóa ( -O) hoặc -C overflow-checks=nođể cho phép phép trừ tràn thay vì hoảng loạn.

fn is_power_of_negative_2(input: i64) -> i64 {
    let sign = input >> 63;
    // 1 op
    let abs_input = (input ^ sign) - sign;
    // 2 ops
    let bad_power_of_two = sign ^ -0x5555_5555_5555_5556; // == 0xaaaa_aaaa_aaaa_aaaa
    // 1 op
    let is_not_power_of_n2 = abs_input & ((abs_input - 1) | bad_power_of_two);
    // 3 ops 
    let is_not_power_of_n2 = (is_not_power_of_n2 | -is_not_power_of_n2) >> 63;
    // 3 ops 
    input & !is_not_power_of_n2
    // 2 ops
}

(Để làm rõ: !xbitwise-KHÔNG ở đây, không logic-KHÔNG)

Các trường hợp thử nghiệm:

#[test]
fn test_is_power_of_negative_2() {
    let mut value = 1;
    for _ in 0 .. 64 {
        assert_ne!(0, is_power_of_negative_2(value), "wrong: {} should return nonzero", value);
        value *= -2;
    }
}

#[test]
fn test_not_power_of_negative_2() {
    for i in &[0, -1, 2, 3, -3, -4, 5, -5, 6, -6, 7, -7, 8, 1<<61, -1<<62, 2554790084739629493, -4676986601000636537] {
        assert_eq!(0, is_power_of_negative_2(*i), "wrong: {} should return zero", i);
    }
}

Hãy thử trực tuyến!


Ý tưởng là kiểm tra xem | x | là lũy thừa 2 (sử dụng (y & (y - 1)) == 0như bình thường). Nếu x là lũy thừa của 2, thì chúng ta sẽ kiểm tra thêm (1) khi nào x >= 0, nó cũng phải là lũy thừa 2, hoặc (2) khi nào x < 0, nó sẽ là một lũy thừa bằng 2. Chúng ta kiểm tra điều này bằng cách &- bad_power_of_two"Mặt nạ 0x Hồi aaaa khi x >= 0(chỉ tạo 0 khi nó là công suất chẵn) hoặc 0xơi 5555 khi x < 0.


Tôi đã đánh cắp ~((r | -r) >> 63)thủ thuật của bạn để hoàn thành việc sửa câu trả lời của tôi.
orlp

6

Haskell, 2 3 hoạt động

import Data.Bits (.&.)

f 0 = False
f 1 = True
f n | n .&. 1 == 0 = f (n `div` -2)
f n | otherwise    = False

Xác định hàm đệ quy f(n). Các hoạt động được sử dụng là gọi hàm ( f), chia ( div) và bitwise và ( .&.).

Không chứa các vòng lặp vì thực tế là Haskell không có câu lệnh lặp :-)


4
Tại sao tôi không ngạc nhiên khi giải pháp Haskell không sử dụng vòng lặp được cung cấp bởi một người có tên "Cơ hội?" =)
Cort Ammon - Phục hồi Monica

1
Tôi rất do dự về f 0, f 1, f n ...ở đây, vì họ là về cơ bản iflà cải trang, mặc dù sau đó một lần nữa, tôi đã cho phép while+ breakvà đầu returns, vì vậy nó có vẻ công bằng. Mặc dù nó dường như tận dụng lợi thế của bộ quy tắc của tôi vô tình bị bỏ ngỏ để giải thích, đó là một giải pháp tốt.
Jason C

3
Đặc biệt là các |s đặc biệt lên trong không khí. Điều đó nói rằng, điều này không vi phạm một quy tắc cụ thể theo cách ít gây tranh cãi: ==Không được phép so sánh . Tuy nhiên, lưu ý rằng nếu cách giải thích của tôi về mã này là chính xác, việc sử dụng booleans ở đây vẻ chấp nhận được vì việc thay thế các giá trị số nguyên tùy ý ở vị trí của chúng dường như không thay đổi kết quả và chúng giống như một dạng trình bày cuối cùng.
Jason C

@JasonC tôi chỉ sử dụng ==vì không có cách nào khác để đúc ra khỏi Intđến Boolhoặc "Truthy" trong Haskell. Liệu kết quả khớp mẫu và bảo vệ có vi phạm ifquy tắc "không s" hay không là cuộc gọi của bạn ;-)
cơ hội

18
Với khớp mẫu, bạn chỉ có thể mã hóa kết quả cho tất cả các số nguyên 64 bit bằng 0 thao tác.
xnor

5

Thao tác Python 3, 10 hoặc 11 9

def g(x):
 while x:
  while 1 - (1 + ~int(x - -2 * int(float(x) / -2))) & 1: x /= -2
  break
 while int(1-x):
     return 0
 return 5  # or any other value

Trả lại 5cho quyền hạn của -2, 0nếu không


Bình luận không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện .
Dennis

5

C, 5 hoạt động

long long f(long long x){
    x=x ^ ((x & 0xaaaaaaaaaaaaaaaa) * 6);
    while(x){
        while(x&(x-1))
            return 0;
        return 1;
    }
    return 0;
}

C, 10 thao tác, không có vòng lặp

long long f(long long x){
    x = x ^ ((x & 0xaaaaaaaaaaaaaaaa) * 6);
    long long t = x & (x-1);
    return (((t-1) & ~t) >> 63) * x;
}

C, 1 hoạt động

long long f(long long x){
    long long a0=1, a1=-2, a2=4, a3=-8, a4=16, a5=-32, a6=64, a7=-128, a8=256, a9=-512, a10=1024, a11=-2048, a12=4096, a13=-8192, a14=16384, a15=-32768, a16=65536, a17=-131072, a18=262144, a19=-524288, a20=1048576, a21=-2097152, a22=4194304, a23=-8388608, a24=16777216, a25=-33554432, a26=67108864, a27=-134217728, a28=268435456, a29=-536870912, a30=1073741824, a31=-2147483648, a32=4294967296, a33=-8589934592, a34=17179869184, a35=-34359738368, a36=68719476736, a37=-137438953472, a38=274877906944, a39=-549755813888, a40=1099511627776, a41=-2199023255552, a42=4398046511104, a43=-8796093022208, a44=17592186044416, a45=-35184372088832, a46=70368744177664, a47=-140737488355328, a48=281474976710656, a49=-562949953421312, a50=1125899906842624, a51=-2251799813685248, a52=4503599627370496, a53=-9007199254740992, a54=18014398509481984, a55=-36028797018963968, a56=72057594037927936, a57=-144115188075855872, a58=288230376151711744, a59=-576460752303423488, a60=1152921504606846976, a61=-2305843009213693952, a62=4611686018427387904, a63=-9223372036854775807-1, a64=0;
    while(a0){
        long long t = x ^ a0;
        long long f = 1;
        while(t){
            f = 0;
            t = 0;
        }
        while(f)
            return 1;
        a0=a1; a1=a2; a2=a3; a3=a4; a4=a5; a5=a6; a6=a7; a7=a8; a8=a9; a9=a10; a10=a11; a11=a12; a12=a13; a13=a14; a14=a15; a15=a16; a16=a17; a17=a18; a18=a19; a19=a20; a20=a21; a21=a22; a22=a23; a23=a24; a24=a25; a25=a26; a26=a27; a27=a28; a28=a29; a29=a30; a30=a31; a31=a32; a32=a33; a33=a34; a34=a35; a35=a36; a36=a37; a37=a38; a38=a39; a39=a40; a40=a41; a41=a42; a42=a43; a43=a44; a44=a45; a45=a46; a46=a47; a47=a48; a48=a49; a49=a50; a50=a51; a51=a52; a52=a53; a53=a54; a54=a55; a55=a56; a56=a57; a57=a58; a58=a59; a59=a60; a60=a61; a61=a62; a62=a63; a63=a64;
    }
    return 0;
}

2
Ôi trời, người cuối cùng chỉ là ác quỷ. Tốt đẹp.
Jason C

4

Lắp ráp, 1 hoạt động

.data

    .space 1         , 1 # (-2)^31
    .space 1610612735, 0
    .space 1         , 1 # (-2)^29
    .space 402653183 , 0
    .space 1         , 1 # (-2)^27
    .space 100663295 , 0
    .space 1         , 1 # (-2)^25
    .space 25165823  , 0
    .space 1         , 1 # (-2)^23
    .space 6291455   , 0
    .space 1         , 1 # (-2)^21
    .space 1572863   , 0
    .space 1         , 1 # (-2)^19
    .space 393215    , 0
    .space 1         , 1 # (-2)^17
    .space 98303     , 0
    .space 1         , 1 # (-2)^15
    .space 24575     , 0
    .space 1         , 1 # (-2)^13
    .space 6143      , 0
    .space 1         , 1 # (-2)^11
    .space 1535      , 0
    .space 1         , 1 # (-2)^9
    .space 383       , 0
    .space 1         , 1 # (-2)^7
    .space 95        , 0
    .space 1         , 1 # (-2)^5 = -32
    .space 23        , 0
    .space 1         , 1 # (-2)^3 = -8
    .space 5         , 0
    .space 1         , 1 # (-2)^1 = -2
    .space 1         , 0
dataZero:
    .space 1         , 0
    .space 1         , 1 # (-2)^0 = 1
    .space 2         , 0
    .space 1         , 1 # (-2)^2 = 4
    .space 11        , 0
    .space 1         , 1 # (-2)^4 = 16
    .space 47        , 0
    .space 1         , 1 # (-2)^6 = 64
    .space 191       , 0
    .space 1         , 1 # (-2)^8
    .space 767       , 0
    .space 1         , 1 # (-2)^10
    .space 3071      , 0
    .space 1         , 1 # (-2)^12
    .space 12287     , 0
    .space 1         , 1 # (-2)^14
    .space 49151     , 0
    .space 1         , 1 # (-2)^16
    .space 196607    , 0
    .space 1         , 1 # (-2)^18
    .space 786431    , 0
    .space 1         , 1 # (-2)^20
    .space 3145727   , 0
    .space 1         , 1 # (-2)^22
    .space 12582911  , 0
    .space 1         , 1 # (-2)^24
    .space 50331647  , 0
    .space 1         , 1 # (-2)^26
    .space 201326591 , 0
    .space 1         , 1 # (-2)^28
    .space 805306367 , 0
    .space 1         , 1 # (-2)^30
    .space 3221225471, 0
    .space 1         , 1 # (-2)^32

.globl isPowNeg2
isPowNeg2:
    movl dataZero(%edi), %eax
    ret

Sử dụng một bảng tra cứu khổng lồ để tìm xem số đó có phải là sức mạnh của 2. Bạn có thể mở rộng số này thành 64 bit, nhưng việc tìm một máy tính để lưu trữ nhiều dữ liệu đó là một bài tập cho người đọc :-P


1
Lập chỉ mục một bảng không phải là một trong các hoạt động được phép.
R ..

1
Ngoài ra, điều này rõ ràng là không thể mở rộng đến 64 bit. :-)
R ..

Thật vậy, việc lập chỉ mục một bảng không có ý định được cho phép theo các quy tắc hiện hành. Tôi đã chỉ định "bạn có thể khai báo các biến" và "bạn có thể chỉ định các số nguyên" với mục đích là vô hướng và về mặt ngữ nghĩa, đây là một mảng (và nói về mặt giáo dục, tôi không cho phép các kiểu mảng cũng như không cho phép lập chỉ mục bất kỳ loại nào như một trong các hoạt động mặc dù bạn có thể gọi nó là "bổ sung" trong ngữ cảnh của trình biên dịch chương trình), nhưng là Cơ hội mà bạn là ... :)
Jason C

3

C, 31 hoạt động

Bản thử trực tiếp

Ý tưởng của tôi rất đơn giản, nếu đó là sức mạnh của hai, thì nếu nhật ký của nó là chẵn thì nó phải dương, nếu không thì nhật ký của nó phải là số lẻ.

int isPositive(int x) // 6
{
    return ((~x & (~x + 1)) >> 31) & 1;
}

int isPowerOfTwo(int x) // 5
{
    return isPositive(x) & ~(x & (x-1));
}

int log2(int x) // 3
{
    int i = (-1);

    while(isPositive(x))
    {
        i  += 1;
        x >>= 1;
    }

    return i;
}

int isPowerOfNegativeTwo(int x) // 17
{
    return (  isPositive(x) &  isPowerOfTwo(x) & ~(log2(x) % 2) )
         | ( ~isPositive(x) & isPowerOfTwo(-x) & (log2(-x) % 2) );
}

1
Bạn thực sự đã làm tốt hơn bạn nghĩ. Một lệnh gọi hàm chỉ được tính là 1, không phải là số lượng toán tử trong hàm. Vì vậy, nếu tôi đã đếm chính xác (kiểm tra hai lần), bạn đã có thứ gì đó như 6 cho isPositive + 5 cho isPowerOfTwo + 3 cho log2 + 17 cho isPowerOfNegativeTwo = 31.
Jason C

1

C, 7 hoạt động

int64_t is_power_of_neg2(int64_t n)
{
    int64_t x = n&-n;
    while (x^n) {
        while (x^-n)
            return 0;
        return x & 0xaaaaaaaaaaaaaaaa;
    }
    return x & 0x5555555555555555;
}

hoặc là:

C, 13 thao tác không có vòng lặp như điều kiện

int64_t is_power_of_neg2(int64_t n)
{
    int64_t s = ~(n>>63);
    int64_t a = ((n/2)^s)-s;
    int64_t x = n&-(uint64_t)n; // Cast to define - on INT64_MIN.
    return ~(a/x >> 63) & x & (0xaaaaaaaaaaaaaaaa^s);
}

Giải trình:

  • n&-nmang lại bit thiết lập thấp nhất của n.
  • alà giá trị tuyệt đối phủ định của n/2, nhất thiết là phủ định vì /2ngăn chặn tràn âm phủ định.
  • a/xlà 0 chỉ khi amột sức mạnh chính xác của hai; mặt khác, ít nhất một bit khác được đặt và nó cao hơn xbit thấp nhất, mang lại kết quả âm.
  • ~(a/x >> 63)sau đó mang lại một bitmask đó là tất cả những gì nếu nhoặc -nlà một sức mạnh của hai, nếu không là tất cả các số không.
  • ^sđược áp dụng cho mặt nạ để kiểm tra dấu hiệu nđể xem nó có phải là sức mạnh của -2.

1

PHP, 3 hoạt động

ternary và ifkhông được phép; Vì vậy, hãy để Lạm dụng lạm dụng while:

function f($n)
{
    while ($n>>1)               # 1. ">>1"
    {
        while ($n&1)            # 2. "&1"
            return 0;
        return f($n/-2|0);      # 3. "/-2" ("|0" to turn it into integer division)
    }
    return $n;
}
  1. $n>>1: nếu số là 0 hoặc 1, số trả về
  2. $n&1: nếu số là số lẻ, trả về 0
  3. kiểm tra khác $n/-2(+ truyền tới int)

0

JavaScript ES6, 7 thao tác

x=>{
  while(x&1^1&x/x){
    x/=-2;x=x|0
  }
  while(x&0xfffffffe)x-=x
  return x
}

Hãy thử trực tuyến!

Giải trình

while(x&1^1&x/x)

Trong khi x! = 0 và x% 2 == 0 4 ops
x / x bằng 1 miễn là x không phải là 0 (0/0 cho NaN được đánh giá là sai)
& bitwise và
x & 1 ^ 1 bằng 1 nếu x là chẵn (x và 1) xor 1

x/=-2;x=x|0

Đây là hình thức phân chia được xác định bởi câu hỏi 1 op

while(x&0xfffffffe)  

Trong khi x! = 1 và x! = 0 1 op
Điều kiện cần để thoát khi x == 0 hoặc x == 1 vì hai giá trị này là giá trị trả về và việc nhập một vòng lặp vô hạn sẽ không hiệu quả. Về mặt lý thuyết có thể được mở rộng cho các giá trị lớn hơn bằng cách tăng số thập lục phân. Hiện đang hoạt động cho tối đa ± 2 ^ 32-1

x-=x

Đặt x thành 0 1 op
Trong khi tôi có thể sử dụng return 0 cho 0 op, tôi cảm thấy rằng bất kỳ vòng lặp while nào bị phá vỡ bởi một câu lệnh khác đều cảm thấy quá giống như gian lận.

return x

trả về x (1 nếu công suất -2, 0 nếu không)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.