Trình cộng nhị phân mù


10

Hãy tưởng tượng bạn có hai hộp B(x)B(y)mỗi hộp chứa một bit không xác định - 0 hoặc 1 và một máy Fcó thể chụp X-quang chúng và tạo ra hộp thứ ba cho B(x^y)( xor ). Fcũng có thể tính toán B(x*y)( ). Trên thực tế, đó chỉ là những trường hợp đặc biệt của hoạt động đơn lẻ mà máy có thể thực hiện - mỗi sản phẩm bên trong , được ký hiệu F()bên dưới.

Đối với hai mảng có cùng độ dài

[B(x[0]), B(x[1]), ..., B(x[n-1])]
[B(y[0]), B(y[1]), ..., B(y[n-1])]

sản phẩm bên trong được định nghĩa là

B(x[0]*y[0] ^ x[1]*y[1] ^ ... ^ x[n-1]*y[n-1])

" Mỗi " có nghĩa là F()có thể xử lý nhiều cặpx[] , y[]trong một lần. Các x[]y[]từ một cặp phải có cùng độ dài; x[]-s và y[]-s từ các cặp khác nhau không nhất thiết phải như vậy.

Hộp được đại diện bởi id số nguyên duy nhất.

Thực hiện sản phẩm bên trong mỗi JavaScript có thể trông giống như

var H=[0,1];          // hidden values, indexed by boxId
function B(x) {       // seal x in a new box and return the box id
  return H.push(x)-1;
}
function F(pairs) {   // "inner product each"
  return pairs.map(function (pair) {
    var r = 0, x = pair[0], y = pair[1];
    for (var i = 0; i < x.length; i++) r ^= H[x[i]] * H[y[i]];
    return B(r);
  })
}

(Vui lòng dịch phần trên sang ngôn ngữ bạn chọn.)

Được cấp quyền truy cập vào một F()triển khai phù hợp với ngôn ngữ của bạn (nhưng không có quyền truy cập vào Hhoặc B()) và được cung cấp hai mảng id hộp tạo thành biểu diễn nhị phân 16 bit của hai số nguyên ab , nhiệm vụ của bạn là tạo id hộp cho biểu diễn nhị phân 16 bit của a+b(loại bỏ tràn) với số lượng F()cuộc gọi tối thiểu .

Giải pháp gọi F()ít lần nhất sẽ thắng. Các mối quan hệ sẽ bị phá vỡ bằng cách đếm tổng số x[],y[]cặpF() được gọi với - ít hơn là tốt hơn. Nếu vẫn bị ràng buộc, kích thước mã của bạn (không bao gồm việc triển khai F()và người trợ giúp) xác định người chiến thắng theo cách chơi gôn mã truyền thống. Vui lòng sử dụng một tiêu đề như "MyLang, 123 cuộc gọi, 456 cặp, 789 byte" cho câu trả lời của bạn.

Viết một hàm hoặc một chương trình hoàn chỉnh. Đầu vào / đầu ra / đối số / kết quả là mảng int ở bất kỳ định dạng hợp lý nào. Đại diện nhị phân có thể là ít hoặc lớn về cuối - chọn một.


Phụ lục 1: Để làm cho thử thách dễ dàng hơn một chút, bạn có thể giả sử rằng các hộp có id 0 và 1 chứa các giá trị 0 và 1. Điều này mang lại cho bạn các hằng số, ví dụ hữu ích cho phủ định (x^1 là "không"). Dĩ nhiên, có nhiều cách xung quanh việc thiếu hằng số, nhưng phần còn lại của thử thách là đủ khó, vì vậy hãy loại bỏ sự phân tâm này.


Phụ lục 2: Để giành được tiền thưởng, bạn phải thực hiện một trong các cách sau:

  • gửi điểm số của bạn (cuộc gọi, cặp, byte) và mã của bạn trước thời hạn

  • gửi điểm số của bạn và băm sha256 của mã của bạn trước thời hạn; sau đó gửi mã thực tế trong vòng 23 giờ sau thời hạn


Nếu tôi dịch nó sang ngôn ngữ mà tôi chọn (Haskell), tôi có thể sử dụng đệ quy giá trị và Fchỉ gọi một lần. Đó chắc chắn là gian lận, nhưng tôi không chắc đó là gian lận tốt hay gian lận xấu.
Christian Sievers

Tôi biết nhà nước toàn cầu không được chào đón ở Haskell, nhưng hãy để tôi hỏi đây là một thử nghiệm tư duy: nếu tôi tăng một bộ đếm toàn cầu trong việc thực hiện F, thì cuối cùng nó sẽ tăng trưởng bao nhiêu? - đó là sự hiểu biết của tôi về "số lượng cuộc gọi".
ngn

Tôi có thể làm chính xác điều đó và nó sẽ nói 1. Nhưng nó không thể được dịch lại thành JavaScript bằng mã của bạn. Về cơ bản tôi sẽ nói y=f(x)và để xphụ thuộc vào y.
Christian Sievers

Tôi sợ tôi không hiểu nó sẽ hoạt động như thế nào. Bạn có thể hiển thị mã mẫu, xin vui lòng? Haskell của tôi rất kém, nhưng tôi chắc chắn rằng tôi có thể tìm ra nếu tôi có thể chơi với mã.
ngn

Có lẽ chúng ta có thể sử dụng các loại sau đây để mô hình hóa vấn đề này? data Box = B Int deriving (Show); f :: [[[Box]]] -> [Box]Tôi sẽ cần thêm thời gian để tìm ra cách thực hiện f(Haskell buộc chữ thường ở đây) - Tôi sẽ thử lại vào ngày mai.
ngn

Câu trả lời:


6

Python 3 , 5 cuộc gọi, 92 cặp, 922 byte

Python 3 , 5 cuộc gọi, 134 cặp, 3120 byte

Python 3 , 6 cuộc gọi, 106 cặp, 2405 byte

[JavaScript (Node.js)], 9 cuộc gọi, 91 cặp, 1405 byte

JavaScript (Node.js), 16 cuộc gọi, 31 cặp, 378 byte

def add(F,a,b):r=[];p=lambda x:(x,x);q=lambda u,v,t:([u,v]+t[0],[u,v]+t[1]);s=lambda c,k,n:([e[j][n]for j in range(k,-1,-1)]+[f[n]],[c]+f[n-k:n+1]);t=lambda c,k,n:q(a[n],b[n],s(c,k,n-1));z=F([p([a[i],b[i]])for i in range(16)]+[([a[i]],[b[i]])for i in range(16)]);e=[z[0:16]];f=z[16:32];r+=[e[0][0]];c=f[0];z=F([p([a[1],b[1],c]),([e[0][1],f[1]],[c,f[1]])]+[([e[0][i]],[e[0][i-1]])for i in range(3,16)]);r+=[z[0]];c=z[1];e+=[[0]*3+z[2:15]];z=F([p([a[2],b[2],c]),t(c,0,3),s(c,1,3)]+[([e[j][i]],[e[1][i-j-1]])for j in range(2)for i in range(6+j,16)]);r+=z[0:2];c=z[2];e+=u(2,4,z[3:]);z=F([p([a[4],b[4],c])]+[t(c,i,i+5)for i in range(0,3)]+[s(c,3,7)]+[([e[j][i]],[e[3][i-j-1]])for j in range(4)for i in range(12+j,16)]);r+=z[0:4];c=z[4];e+=u(4,8,z[5:]);z=F([p([a[8],b[8],c])]+[t(c,i,i+9) for i in range(0,7)]);return r+z
def u(b,e,z):
	j=0;w=[0]*(e-b)
	for i in range(b,e):w[i-b]=[0]*(i+e)+z[j:j+16-(i+e)];j+=16-(i+e)
	return w

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

PHIÊN BẢN ĐẦU TIÊN Được rồi, không chơi gôn. Nó chỉ là một bản chuyển thể của mã @ ngn.

Ý tưởng duy nhất ở đây là bạn không cần phải tính toán lần thực hiện cuối cùng kể từ khi bạn loại bỏ tràn. Ngoài ra, các cuộc gọi của Fđược nhóm theo hai. Có thể chúng có thể được nhóm theo một cách khác, nhưng tôi nghi ngờ bạn có thể giảm đáng kể số lượng cặp, do bản chất của thuật toán bổ sung cơ bản.

EDIT : Vẫn chưa chơi golf. Số lượng các cặp chắc chắn có thể giảm và có lẽ số lượng cuộc gọi cũng vậy. Xem https://gist.github.com/jferard/864f4be6e4b63979da176bff380e6c62 để biết "bằng chứng" với sympy.

CHỈNH SỬA 2 Chuyển sang Python vì nó dễ đọc hơn đối với tôi. Bây giờ tôi đã có công thức chung, tôi nghĩ rằng tôi có thể đạt đến giới hạn 5 (có thể 4) cuộc gọi.

EDIT 3 Dưới đây là những viên gạch cơ bản:

alpha[i] = a[i] ^ b[i]
beta[i] = a[i] * b[i]
c[0] = beta[0]
r[0] = alpha[0]

Công thức chung là:

c[i] = alpha[i]*c[i-1] ^ beta[i]
r[i] = a[i] ^ b[i] ^ c[i-1]

Phiên bản mở rộng là:

c[0] = beta[0]
c[1] = alpha[1]*beta[0] ^ beta[1]
c[2] = alpha[2]*alpha[1]*beta[0] ^ alpha[2]*beta[1] ^ beta[2]
c[3] = alpha[3]*alpha[2]*alpha[1]*beta[0] ^ alpha[3]*alpha[2]*beta[1] ^ alpha[3]*beta[2] ^ beta[3]
...
c[i] = alpha[i]*...*alpha[1]*beta[0] ^ alpha[i]*...*alpha[2]*beta[1] ^ .... ^ alpha[i]*beta[i-1] ^ beta[i]

5 cuộc gọi dường như là giới hạn đối với tôi. Bây giờ tôi có một công việc nhỏ để loại bỏ các cặp và chơi golf đó!

CHỈNH SỬA 4 Tôi đã đánh gôn này.

Phiên bản bị đánh cắp:

def add(F, a, b):
    r=[]
    # p is a convenient way to express x1^x2^...x^n
    p = lambda x:(x,x)
    # q is a convenient way to express a[i]^b[i]^carry[i-1]
    q = lambda u,v,t:([u,v]+t[0],[u,v]+t[1])

    # step1: the basic bricks
    z=F([p([a[i],b[i]]) for i in range(16)]+[([a[i]],[b[i]]) for i in range(16)])
    alpha=z[0:16];beta=z[16:32]
    r.append(alpha[0])
    c = beta[0]

    # step 2
    z=F([
        p([a[1],b[1],c]),
        ([alpha[1],beta[1]],[c,beta[1]])
        ]+[([alpha[i]],[alpha[i-1]]) for i in range(3,16)])
    r.append(z[0])
    c = z[1] # c[1]
    alpha2=[0]*3+z[2:15]
    assert len(z)==15, len(z)

    # step 3
    t0=([alpha[2],beta[2]],[c,beta[2]])
    t1=([alpha2[3],alpha[3],beta[3]],[c,beta[2],beta[3]])
    z=F([
        p([a[2],b[2],c]),
        q(a[3],b[3],t0),
        t1]+
        [([alpha[i]],[alpha2[i-1]]) for i in range(6,16)]+
        [([alpha2[i]],[alpha2[i-2]]) for i in range(7,16)])
    r.extend(z[0:2])
    c = z[2] # c[3]
    alpha3=[0]*6+z[3:13]
    alpha4=[0]*7+z[13:22]
    assert len(z)==22, len(z)

    # step 4
    t0=([alpha[4],beta[4]],[c,beta[4]])
    t1=([alpha2[5],alpha[5],beta[5]],[c,beta[4],beta[5]])
    t2=([alpha3[6],alpha2[6],alpha[6],beta[6]],[c,beta[4],beta[5],beta[6]])
    t3=([alpha4[7],alpha3[7],alpha2[7],alpha[7],beta[7]],[c,beta[4],beta[5],beta[6],beta[7]])
    z=F([
        p([a[4],b[4],c]),
        q(a[5],b[5],t0),
        q(a[6],b[6],t1),
        q(a[7],b[7],t2),
        t3]+
        [([alpha[i]],[alpha4[i-1]]) for i in range(12,16)]+
        [([alpha2[i]],[alpha4[i-2]]) for i in range(13,16)]+
        [([alpha3[i]],[alpha4[i-3]]) for i in range(14,16)]+
        [([alpha4[i]],[alpha4[i-4]]) for i in range(15,16)])
    r.extend(z[0:4])
    c = z[4] # c[7]
    alpha5 = [0]*12+z[5:9]
    alpha6 = [0]*13+z[9:12]
    alpha7 = [0]*14+z[12:14]
    alpha8 = [0]*15+z[14:15]
    assert len(z) == 15, len(z)

    # step 5
    t0=([alpha[8],beta[8]],[c,beta[8]])
    t1=([alpha2[9],alpha[9],beta[9]],[c,beta[8],beta[9]])
    t2=([alpha3[10],alpha2[10],alpha[10],beta[10]],[c,beta[8],beta[9],beta[10]])
    t3=([alpha4[11],alpha3[11],alpha2[11],alpha[11],beta[11]],[c,beta[8],beta[9],beta[10],beta[11]])
    t4=([alpha5[12],alpha4[12],alpha3[12],alpha2[12],alpha[12],beta[12]],[c,beta[8],beta[9],beta[10],beta[11],beta[12]])
    t5=([alpha6[13],alpha5[13],alpha4[13],alpha3[13],alpha2[13],alpha[13],beta[13]],[c,beta[8],beta[9],beta[10],beta[11],beta[12],beta[13]])
    t6=([alpha7[14],alpha6[14],alpha5[14],alpha4[14],alpha3[14],alpha2[14],alpha[14],beta[14]],[c,beta[8],beta[9],beta[10],beta[11],beta[12],beta[13],beta[14]])
    t7=([alpha8[15],alpha7[15],alpha6[15],alpha5[15],alpha4[15],alpha3[15],alpha2[15],alpha[15],beta[15]],[c,beta[8],beta[9],beta[10],beta[11],beta[12],beta[13],beta[14],beta[15]])

    z=F([
        p([a[8],b[8],c]),
        q(a[9],b[9],t0),
        q(a[10],b[10],t1),
        q(a[11],b[11],t2),
        q(a[12],b[12],t3),
        q(a[13],b[13],t4),
        q(a[14],b[14],t5),
        q(a[15],b[15],t6)
    ])
    r.extend(z)
    return r

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


Rất tốt :) Bạn tìm thấy hai tối ưu hóa dễ dàng mà tôi đã bỏ qua trên mục đích. "Tôi nghi ngờ bạn có thể giảm đáng kể số lượng cặp" - lưu ý rằng tiêu chí đầu tiên để chiến thắng là số lượng cuộc gọi đến F(). Tôi đảm bảo có một cách để giảm đáng kể những điều đó (đó là phần khó nhất của thử thách này), và sau đó sẽ có chỗ để tối ưu hóa số lượng cặp, và cuối cùng tất nhiên là đánh gôn (nhưng đó là tiêu chí ít quan trọng nhất).
ngn

Ok tôi hiểu rồi Sớm hay muộn, bạn đã có một cái gì đó như thế : ... + x * y * z + .... Chúng tôi không thể sử dụng Fđể đánh giá nó, nhưng nếu chúng tôi đã tính toán x * yvới Fcuộc gọi trước đó , chúng tôi chỉ phải làm: ... + (x * y) * z + ...(nó phù hợp với định dạng của F). Chơi với sympy, tôi quản lý để thực hiện một cuộc gọi (bước 1: tính r0, c0, r1; step2: tính c1 và một số giá trị phụ trợ; bước 3: tính r2, c2, r3, c3) và bây giờ tôi đang nới lỏng giải pháp.
jferard

Đúng, nói cách khác: các bit đầu ra là đa thức bậc 2 cao hơn 2 trong các bit đầu vào. Sản phẩm bên trong có thể kết hợp một đa thức m độ và n độ thành một đa thức (m + n) -degree, nhiều nhất. Đừng vội vàng - trong vài giờ nữa tôi sẽ có thể thiết lập tiền thưởng :)
ngn

Bạn có thể muốn xem xét việc tận dụng Phụ lục 2 ở trên. Hoặc nếu không: nếu ai đó sao chép mã của bạn, xóa một khoảng trắng và đăng lại mã đó, về mặt kỹ thuật tôi sẽ phải trao phần thưởng cho họ.
ngn

2
Đối với bản ghi, không thể sử dụng ít hơn năm cuộc gọi, vì giải pháp yêu cầu đa thức 32 độ. (Đa thức tương ứng với bất kỳ chức năng nào của các bit đầu vào là duy nhất.)
Nitrodon

2

Haskell, 1 cuộc gọi (gian lận ???), 32 cặp (có thể được cải thiện), 283 byte (giống nhau)

Xin đừng giận tôi, tôi không muốn chiến thắng với điều này, nhưng tôi được khuyến khích trong những nhận xét về thử thách để giải thích những gì tôi đang nói.

Tôi đã cố gắng sử dụng đơn vị nhà nước để xử lý việc thêm các hộp và đếm các cuộc gọi và cặp, và điều đó đã có hiệu quả, nhưng tôi đã không quản lý để làm cho giải pháp của mình hoạt động trong cài đặt đó. Vì vậy, tôi đã làm những gì cũng được đề xuất trong các bình luận: chỉ cần ẩn dữ liệu đằng sau một hàm tạo dữ liệu và không nhìn trộm. (Cách rõ ràng sẽ là sử dụng một mô-đun riêng biệt và không xuất khẩu hàm tạo.) Phiên bản này có ưu điểm là đơn giản hơn nhiều.

Vì chúng ta đang nói về các hộp bit, tôi đặt Boolcác giá trị vào chúng. Tôi định nghĩa zerolà hộp đã cho với bit 0 - onekhông cần thiết.

import Debug.Trace

data B = B { unB :: Bool }

zero :: B
zero = B False

f :: [([B],[B])] -> [B]
f pairs =  trace ("f was called with " ++ show (length pairs) ++ " pairs") $
           let (B i) &&& (B j) = i && j
           in map (\(x,y) ->  B ( foldl1 (/=) (zipWith (&&&) x y))) pairs

Chúng tôi đang sử dụng chức năng gỡ lỗi traceđể xem tần suất fđược gọi và với bao nhiêu cặp. &&&nhìn vào các hộp bằng cách khớp mẫu, bất đẳng thức /= được sử dụng trên Boolcác giá trị là xor.

bits :: Int -> [Bool]
bits n = bitsh n 16
  where bitsh _ 0 = []
        bitsh n k = odd n : bitsh (n `div` 2) (k-1)

test :: ( [B] -> [B] -> [B] ) -> Int -> Int -> Bool
test bba n m = let x = map B (bits n)
                   y = map B (bits m)
                   r = bba x y
                   res = map unB r
               in res==bits(n+m)

Các testchức năng có một bộ cộng nhị phân mù như là đối số đầu tiên, và sau đó hai số mà bổ sung được thử nghiệm. Nó trả về một Booldấu hiệu cho biết thử nghiệm đã thành công hay chưa. Đầu tiên các hộp đầu vào được tạo, sau đó bộ cộng được gọi, kết quả được bỏ hộp (với unB) và so sánh với kết quả mong đợi.

Tôi đã triển khai hai bộ cộng, giải pháp mẫu simple, để chúng ta có thể thấy rằng đầu ra gỡ lỗi hoạt động chính xác và giải pháp của tôi sử dụng đệ quy giá trị valrec.

simple a b = let [r0] = f [([a!!0,b!!0],[a!!0,b!!0])]
                 [c]  = f [([a!!0],[b!!0])]
             in loop 1 [r0] c
             where loop 16 rs _ = rs
                   loop i  rs c = let [ri] = f [([a!!i,b!!i,c],[a!!i,b!!i,c])]
                                      [c'] = f [([a!!i,b!!i,c],[b!!i,c,a!!i])]
                                  in loop (i+1) (rs++[ri]) c'

valrec a b =
    let res = f (pairs res a b)
    in [ res!!i | i<-[0,2..30] ]
  where pairs res a b =
           let ts = zipWith3 (\x y z -> [x,y,z])
                             a b (zero : [ res!!i | i<-[1,3..29] ]) in
           [ p | t@(h:r) <- ts, p <- [ (t,t), (t,r++[h]) ] ]

Xem cách tôi xác định resvề mặt chính nó? Điều đó còn được gọi là buộc nút .

Bây giờ chúng ta có thể thấy làm thế nào fchỉ được gọi một lần:

*Main> test valrec 123 456
f was called with 32 pairs
True

Hoặc thay thế valrecbằng cách simplexem fđược gọi 32 lần.

Hãy thử trực tuyến! (đầu ra theo dõi xuất hiện dưới "Gỡ lỗi")


Không có sự tức giận ở đây :) Vì vậy, nếu tôi hiểu chính xác, đối số flà một danh sách lười biếng, có khả năng vô hạn mà cụ thể hóa khi bạn lặp qua nó? Tôi e rằng điều đó trái với tinh thần của thử thách - nó cho phép bạn trì hoãn quyết định về những gì sẽ vượt qua như là i+1đối số thứ nhất cho đến khi bạn nhận được kết quả tương ứng với i-th. Thật thú vị hơn nhiều khi tìm hiểu có bao nhiêu cuộc gọi fmà bạn sẽ cần với các đối số hoàn toàn cụ thể hóa, không thay đổi :)
ngn

Tôi đồng ý. @jferard đã thực hiện một công việc tuyệt vời không nên bị vô hiệu bởi một mánh khóe như vậy. Mặc dù fcó thể lấy đầu vào vô hạn (thêm luồng bit vô hạn, yay!), Đó không phải là điểm. Ồ, và thực sự tracethông điệp đảm bảo rằng độ dài là hữu hạn và được biết ngay từ đầu. Ngoài ra, tôi sẽ không nói rằng có một quyết định hoãn lại: mọi thứ đã được lên kế hoạch trước thời hạn, vì yêu cầu tôi chỉ là những hộp xáo trộn mù quáng. Và lưu ý rằng đó không phải là về thứ tự của các đối số: Tôi có thể thay đổi nó để reschứa kết quả đầu tiên và sau đó là các bit mang.
Christian Sievers

"Tôi chỉ là những hộp xáo trộn mù quáng" - Giả sử bạn đã nhận được một hộp từ cuộc gọi f; Bạn có phản hồi lại hộp đó như một đối số khác trong cùng một lệnh gọi fkhông?
ngn

Vâng tôi đồng ý. Đó là những gì giá trị đệ quy là tất cả về. Bạn đã đúng: đó là sử dụng sự lười biếng và thực tế là tôi có thể sử dụng các đối số không được cụ thể hóa hoàn toàn (tôi thích mô tả đó). Với tinh thần rõ ràng của thách thức, đó là - như đã thông báo - rõ ràng là gian lận. Nếu một người nghĩ rằng đó là sáng tạo hoặc đáng chú ý, người ta có thể lập luận rằng đó là gian lận tốt.
Christian Sievers

Đó chắc chắn là loại tốt - rõ ràng bạn không có ý định lừa dối ở đây. Lười trong lập trình chức năng là một khái niệm đẹp và nó có những công dụng hợp lệ của nó. Khi tôi cố gắng học một số Haskell vài năm trước, tôi nhớ rằng mình rất ấn tượng với một lớp lót "liên kết nút thắt" cho các số Fibonacci.
ngn

0

JavaScript, 32 cuộc gọi, 32 cặp, 388 byte

Dyalog APL, 32 cuộc gọi, 32 cặp, 270 byte

Đây là một giải pháp mẫu ngây thơ có thể phục vụ như một mẫu.

Lưu ý rằng số byte phải chỉ bao gồm phần được bao quanh với "BEGIN / END GIẢI PHÁP".

Giải trình:

Tôi đã chọn thứ tự bit endian nhỏ ( x[0]là bit ít quan trọng nhất).

Quan sát rằng mod 2 bổ sung một bit có thể được nhận ra là F([[[x,y],[x,y]]])(nghĩa là: x*x ^ y*y- phép nhân mod 2 là idempotent) và phép nhân nhị phân là F([[[x],[y]]]).

Chúng tôi duyệt qua các bit từ ít nhất có ý nghĩa đến quan trọng nhất và ở mỗi bước tính toán một bit kết quả và thực hiện.

#!/usr/bin/env node
'use strict'
let H=[0,1]
,B=x=>H.push(x)-1
,nCalls=0
,nPairs=0
,F=pairs=>{
  nCalls++;nPairs+=pairs.length
  return pairs.map(([x,y])=>{let s=0;for(let i=0;i<x.length;i++)s^=H[x[i]]*H[y[i]];return B(s)})
}

// -----BEGIN SOLUTION-----
var f=(a,b)=>{
  var r=[], c // r:result bits (as box ids), c:carry (as a box id)
  r[0]=F([[[a[0],b[0]],[a[0],b[0]]]])          // r0 = a0 ^ b0
  c=F([[[a[0]],[b[0]]]])                       // c = a0*b0
  for(var i=1;i<16;i++){
    r.push(F([[[a[i],b[i],c],[a[i],b[i],c]]])) // ri = ai ^ bi ^ c
    c=F([[[a[i],b[i],c],[b[i],c,a[i]]]])       // c = ai*bi ^ bi*c ^ c*ai
  }
  return r
}
// -----END SOLUTION-----

// tests
let bits=x=>{let r=[];for(let i=0;i<16;i++){r.push(x&1);x>>=1}return r}
,test=(a,b)=>{
  console.info(bits(a))
  console.info(bits(b))
  nCalls=nPairs=0
  let r=f(bits(a).map(B),bits(b).map(B))
  console.info(r.map(x=>H[x]))
  console.info('calls:'+nCalls+',pairs:'+nPairs)
  console.assert(bits(a+b).every((x,i)=>x===H[r[i]]))
}

test(12345,6789)
test(12,3)
test(35342,36789)

Điều tương tự trong Dyalog APL (nhưng sử dụng id hộp ngẫu nhiên):

⎕io←0⋄K←(V←⍳2),2+?⍨1e6⋄B←{(V,←⍵)⊢K[≢V]}⋄S←0⋄F←{S+←1,≢⍵⋄B¨2|+/×/V[K⍳↑⍉∘↑¨⍵]}
⍝ -----BEGIN SOLUTION-----
f←{
  r←F,⊂2⍴⊂⊃¨⍺⍵        ⍝ r0 = a0 ^ b0
  c←⊃F,⊂,¨⊃¨⍺⍵        ⍝ c = a0*b0
  r,⊃{
    ri←⊃F,⊂2⍴⊂⍺⍵c     ⍝ ri = ai ^ bi ^ c
    c⊢←⊃F,⊂(⍺⍵c)(⍵c⍺) ⍝ c = ai*bi ^ bi*c ^ c*ai
    ri
  }¨/1↓¨⍺⍵
}
⍝ -----END SOLUTION-----
bits←{⌽(16⍴2)⊤⍵}
test←{S⊢←0⋄r←⊃f/B¨¨bits¨⍺⍵
      ⎕←(↑bits¨⍺⍵)⍪V[K⍳r]⋄⎕←'calls:' 'pairs:',¨S
      (bits⍺+⍵)≢V[K⍳r]:⎕←'wrong!'}
test/¨(12345 6789)(12 3)(35342 36789)
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.