Thử thách hàm băm có thể Tweet


73

Trong này bạn sẽ viết hàm băm bằng 140 byte 1 hoặc ít hơn mã nguồn. Hàm băm phải lấy một chuỗi ASCII làm đầu vào và trả về số nguyên không dấu 24 bit ([0, 2 24 -1]) làm đầu ra.

Hàm băm của bạn sẽ được đánh giá cho mỗi từ trong từ điển tiếng Anh 2 lớn này . Điểm của bạn là lượng từ chia sẻ giá trị băm với một từ khác (xung đột).

Điểm số thấp nhất chiến thắng, mối quan hệ bị phá vỡ bởi poster đầu tiên.

Trường hợp thử nghiệm

Trước khi gửi, vui lòng kiểm tra tập lệnh ghi điểm của bạn trên đầu vào sau:

duplicate
duplicate
duplicate
duplicate

Nếu nó cho bất kỳ điểm nào ngoài 4, thì đó là lỗi.


Làm rõ các quy tắc:

  1. Hàm băm của bạn phải chạy trên một chuỗi, không phải toàn bộ mảng. Ngoài ra, hàm băm của bạn có thể không thực hiện bất kỳ I / O nào khác ngoài chuỗi đầu vào và số nguyên đầu ra.
  2. Các hàm băm tích hợp hoặc chức năng tương tự (ví dụ mã hóa để xáo trộn byte) không được phép.
  3. Hàm băm của bạn phải có tính xác định.
  4. Trái với hầu hết các cuộc thi khác, tối ưu hóa cụ thể cho đầu vào tính điểm được cho phép.

1 Tôi biết Twitter giới hạn các ký tự thay vì byte, nhưng để đơn giản, chúng tôi sẽ sử dụng byte làm giới hạn cho thử thách này.
2 Được sửa đổi từ rất lớn của Debian , loại bỏ mọi từ không phải ASCII.


11
Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch's? Cái gì...?
Luis Mendo

8
@DonMuesli en.wikipedia.org/wiki/Llanfairpwllgwyngyll (sự thật thú vị: từ đó cũng có trong từ điển nén tích hợp của Jelly)
Martin Ender

8
Tôi nghĩ bạn không nên cho phép từ điển tích hợp.
Dennis

4
Để tham khảo: Lấy 24 MSB của SHA-512 sẽ đạt được số điểm là 6816.
Dennis

10
Một số tính toán ngược của phong bì: Với các D=340275từ và R=2^24kết quả băm, một hàm băm ngẫu nhiên có một D^2/(2*R) = 3450cặp va chạm dự kiến , một số trong đó trùng lặp. Có một D^3/(6*R^2) = 23bộ ba va chạm dự kiến và số lượng va chạm lớn hơn không đáng kể, có nghĩa là những bộ ba này có khả năng rời rạc. Điều này cung cấp một 6829từ dự kiến chia sẻ giá trị băm, ~ 70trong ba lần và phần còn lại theo cặp. Độ lệch chuẩn được ước tính 118, do đó, <6200với một hàm băm ngẫu nhiên là khoảng 5 sự kiện sigma.
xnor

Câu trả lời:


11

Được rồi, tôi sẽ đi học một ngôn ngữ chơi gôn.

CJam, 140 byte, 3314 từ va chạm

00000000: 7b5f 3162 225e d466 4a55 a05e 9f47 fc51  {_1b"^.fJU.^.G.Q
00000010: c45b 4965 3073 72dd e1b4 d887 a4ac bcbd  .[Ie0sr.........
00000020: 9c8f 70ca 2981 b2df 745a 10d0 dfca 6cff  ..p.)...tZ....l.
00000030: 7a3b 64df e730 54b4 b068 8584 5f6c 9f6b  z;d..0T..h.._l.k
00000040: b7f8 7a1f a2d3 b2b8 bcf5 cfa6 1ef7 a55c  ..z............\
00000050: dca8 795c 2492 dc32 1fb6 f449 f9ca f6b7  ..y\$..2...I....
00000060: a2cf 4772 266e ad4f d90c d236 b51d c5d5  ..Gr&n.O...6....
00000070: 5c46 3f9b 7cb4 f195 4efc fe4a ce8d 9aee  \F?.|...N..J....
00000080: 9dbc 223d 6962 3443 2329 257d            .."=ib4C#)%}

Xác định một khối (hàm ẩn danh). Để kiểm tra, bạn có thể thêm qN%%N*Nđể lấy danh sách các từ được phân tách bằng dòng mới trên stdin và viết một danh sách băm được phân tách bằng dòng mới trên thiết bị xuất chuẩn. Mã Python tương đương:

b=lambda s,a:reduce(lambda n,c:n*a+ord(c),s,0)
f=lambda s:b(s,ord('^\xd4fJU\xa0^\x9fG\xfcQ\xc4[Ie0sr\xdd\xe1\xb4\xd8\x87\xa4\xac\xbc\xbd\x9c\x8fp\xca)\x81\xb2\xdftZ\x10\xd0\xdf\xcal\xffz;d\xdf\xe70T\xb4\xb0h\x85\x84_l\x9fk\xb7\xf8z\x1f\xa2\xd3\xb2\xb8\xbc\xf5\xcf\xa6\x1e\xf7\xa5\\\xdc\xa8y\\$\x92\xdc2\x1f\xb6\xf4I\xf9\xca\xf6\xb7\xa2\xcfGr&n\xadO\xd9\x0c\xd26\xb5\x1d\xc5\xd5\\F?\x9b|\xb4\xf1\x95N\xfc\xfeJ\xce\x8d\x9a\xee\x9d\xbc'[b(s,1)%125]))%(8**8+1)

Pyth, 140 byte, 3535 3396 từ va chạm

00000000: 4c25 4362 2d68 5e38 2038 2a36 3643 4022  L%Cb-h^8 8*66C@"
00000010: aa07 f29a 27a7 133a 3901 484d 3f9b 1982  ....'..:9.HM?...
00000020: d261 79ab adab 9d92 888c 3012 a280 76cf  .ay.......0...v.
00000030: a2e5 8f81 7039 acee c42e bc18 28d8 efbf  ....p9......(...
00000040: 0ebe 2910 9c90 158e 3742 71b4 bdf5 59c2  ..).....7Bq...Y.
00000050: f90b e291 8673 ea59 6975 10be e750 84c8  .....s.Yiu...P..
00000060: 0b0f e7e8 f591 f628 cefa 1ab3 2e3c 72a3  .......(.....<r.
00000070: 7f09 6190 dbd2 d54e d6d0 d391 a780 ebb6  ..a....N........
00000080: ae86 2d1e 49b0 552e 7522 4362            ..-.I.U.u"Cb

Xác định một hàm có tên y. Để kiểm tra, bạn có thể thêm jmyd.zđể lấy danh sách các từ được phân tách bằng dòng mới trên stdin và viết một danh sách băm được phân tách bằng dòng mới trên thiết bị xuất chuẩn. Mã Python tương đương:

b=lambda s,a:reduce(lambda n,c:n*a+ord(c),s,0)
f=lambda s:b(s,256)%(8**8+1-66*ord("\xaa\x07\xf2\x9a'\xa7\x13:9\x01HM?\x9b\x19\x82\xd2ay\xab\xad\xab\x9d\x92\x88\x8c0\x12\xa2\x80v\xcf\xa2\xe5\x8f\x81p9\xac\xee\xc4.\xbc\x18(\xd8\xef\xbf\x0e\xbe)\x10\x9c\x90\x15\x8e7Bq\xb4\xbd\xf5Y\xc2\xf9\x0b\xe2\x91\x86s\xeaYiu\x10\xbe\xe7P\x84\xc8\x0b\x0f\xe7\xe8\xf5\x91\xf6(\xce\xfa\x1a\xb3.<r\xa3\x7f\ta\x90\xdb\xd2\xd5N\xd6\xd0\xd3\x91\xa7\x80\xeb\xb6\xae\x86-\x1eI\xb0U.u"[b(s,256)%121]))

Giới hạn lý thuyết

Làm thế nào tốt chúng ta có thể mong đợi để làm gì? Dưới đây là một âm mưu của x, số lượng các từ va chạm, so với y, entropy tính theo byte cần thiết để có được nhiều nhất các từ x va chạm. Ví dụ: điểm (2835, 140) cho chúng ta biết rằng một hàm ngẫu nhiên có nhiều nhất là 2835 từ va chạm với xác suất 1/256 ** 140, do đó, rất khó có khả năng chúng ta sẽ có thể làm tốt hơn nhiều so với 140 byte mã.

đồ thị


Phân tích tốt đẹp của các giới hạn lý thuyết. Để vượt qua giới hạn lý thuyết đó, có lẽ người ta sẽ phải sử dụng một ngôn ngữ với các hàm dựng sẵn được tối ưu hóa cho từ điển trong câu hỏi (sẽ là gian lận). Nếu ngôn ngữ có hàm băm mật mã dựng sẵn, giới hạn có thể được biến thành một phương pháp mang tính xây dựng nhiều hơn hoặc ít hơn để tìm một giải pháp tối ưu. Hãy xem xét điều này: $ h (w || c)% 2 ^ {24} $ trong đó $ c $ là hằng số chuỗi byte. Trong một mô hình nhà tiên tri ngẫu nhiên có thể được hiển thị để tiến gần đến mức tối ưu với xác suất cao. Tất nhiên, vũ phu buộc $ c $ sẽ không khả thi.
kasperd

Làm thế nào bạn tính toán công thức cho biểu đồ? Thật sự thú vị!
NikoNyrh

@NikoNyrh Lập trình động. Hãy ( w , c , h ) đại diện cho một nhà nước với w lời, trong đó c đang va chạm với h băm riêng biệt, và số còn lại w - c đều có băm riêng biệt. Nếu chúng ta thêm một từ ngẫu nhiên, trạng thái trở thành ( w + 1, c , h ) với xác suất 1 - ( h + w - c ) / 2 ^ 24 hoặc ( w + 1, c + 1, h ) với xác suất h / 2 ^ 24 hoặc ( w + 1, c+ 2, h + 1) với xác suất ( w - c ) / 2 ^ 24. Sau đó, entropy cuối cùng được vẽ bằng các từ x va chạm là cơ sở nhật ký 1/256 của tổng xác suất tại các trạng thái (340275, c , h ) với cx .
Anders Kaseorg

Tôi không thể tin rằng không ai hỏi làm thế nào bạn đưa ra hàm băm? Tôi sẽ rất quan tâm để biết.
Anush

22

Con trăn, 5333 4991

Tôi tin rằng đây là ứng cử viên đầu tiên đạt điểm cao hơn đáng kể so với một lời sấm truyền ngẫu nhiên.

def H(s):n=int(s.encode('hex'),16);return n%(8**8-ord('+%:5O![/5;QwrXsIf]\'k#!__u5O}nQ~{;/~{CutM;ItulA{uOk_7"ud-o?y<Cn~-`bl_Yb'[n%70]))

1
Phù thủy! def H(s):n=int(s.encode('hex'),16);return n%...tiết kiệm 5 byte, trong trường hợp bạn có thể sử dụng chúng bằng cách nào đó ...
Dennis

3
@Dennis Tôi có thể đã sử dụng 5 byte để làm cho chuỗi không đổi dài hơn 5 byte. Nhưng tôi sẽ phải bắt đầu xây dựng chuỗi không đổi từ đầu nếu tôi thay đổi độ dài. Và tôi không chắc rằng 5 byte đó sẽ cho tôi sự cải thiện đủ để bắt đầu xây dựng chuỗi. Tôi đã dành hàng giờ thời gian CPU để tối ưu hóa hằng chuỗi.
kasperd

@Dennis Tôi đoán thêm một vài byte sẽ cho tôi tự do sử dụng một số ký tự trong liên tục cần thoát. Bằng cách đó, tôi có khả năng có thể sử dụng thêm một vài byte mà không phải xây dựng lại chuỗi.
kasperd

7
Nếu bạn muốn một byte khác , 2**24 == 8**8.
Anders Kaseorg

20

Python 2, 140 byte, 4266 từ va chạm

Tôi đã không thực sự muốn bắt đầu với thứ byte không thể in được do tính tweet không rõ ràng của chúng, nhưng tốt, tôi đã không bắt đầu nó. :-P

00000000: efbb bf64 6566 2066 2873 293a 6e3d 696e  ...def f(s):n=in
00000010: 7428 732e 656e 636f 6465 2827 6865 7827  t(s.encode('hex'
00000020: 292c 3336 293b 7265 7475 726e 206e 2528  ),36);return n%(
00000030: 382a 2a38 2b31 2d32 3130 2a6f 7264 2827  8**8+1-210*ord('
00000040: 6f8e 474c 9f5a b49a 01ad c47f cf84 7b53  o.GL.Z........{S
00000050: 49ea c71b 29cb 929a a53b fc62 3afb e38e  I...)....;.b:...
00000060: e533 7360 982a 50a0 2a82 1f7d 768c 7877  .3s`.*P.*..}v.xw
00000070: d78a cb4f c5ef 9bdb 57b4 7745 3a07 8cb0  ...O....W.wE:...
00000080: 868f a927 5b6e 2536 375d 2929            ...'[n%67]))

Python 2, 140 byte có thể in, 4662 4471 4362 từ va chạm

def f(s):n=int(s.encode('hex'),16);return n%(8**8+3-60*ord('4BZp%(jTvy"WTf.[Lbjk6,-[LVbSvF[Vtw2e,NsR?:VxC0h5%m}F5,%d7Kt5@SxSYX-=$N>'[n%71]))

Lấy cảm hứng từ hình thức giải pháp của kasperd, rõ ràng là nhưng nhưng với sự bổ sung quan trọng của một phép biến đổi affine trên không gian mô đun và các tham số hoàn toàn khác nhau.


+1 Tôi không bỏ cuộc nếu không chiến đấu. Nhưng tôi nghĩ rằng tôi phải ngừng tối ưu hóa giải pháp hiện tại của mình và tìm một cách tiếp cận khác, bởi vì tôi sẽ không đánh bại bạn nếu tôi tiếp tục sử dụng phương pháp hiện tại của mình để tối ưu hóa các tham số. Tôi sẽ trở lại với một chỉnh sửa cho giải pháp của tôi một khi tôi đã đánh bại bạn ....
kasperd

@kasperd: Tuyệt vời, mang nó lên. :-P
Anders Kaseorg

1
@AndersKaseorg Làm thế nào để bạn tìm thấy chuỗi?
ASCII chỉ

@AndersKaseorg Tôi đã tăng tốc tìm kiếm thông số của mình rất nhiều. Và tôi đã loại bỏ một trở ngại khiến cho việc tìm kiếm của tôi bị mắc kẹt với các giải pháp tối ưu. Nhưng tôi vẫn không thể làm cho nó tốt hơn 4885. Sau khi suy nghĩ về lý do tại sao tôi không thể làm cho nó thêm nữa, tôi đột nhiên nhận ra điều gì không ổn với giải pháp của mình và cách khắc phục. Bây giờ sự chuyển đổi affine trong giải pháp của bạn có ý nghĩa hoàn hảo với tôi. Tôi nghĩ rằng cách duy nhất tôi có thể có thể bắt kịp là bằng cách sử dụng một phép biến đổi affine.
kasperd

1
@kasperd: Rất đẹp. Khi tìm kiếm một chuỗi tốt hơn n%(8**8-ord('…'[n%70]))mà không có thay đổi tham số khác, tôi chỉ tìm được đến 4995, vì vậy có vẻ như trình tối ưu hóa mới của bạn đã bắt kịp tôi. Bây giờ điều này trở nên thú vị hơn!
Anders Kaseorg

16

CJam, 4125 3937 3791 3677

0000000: 7b 5f 39 62 31 31 30 25 5f 22 7d 13 25 77  {_9b110%_"}.%w
000000e: 77 5c 22 0c e1 f5 7b 83 45 85 c0 ed 08 10  w\"...{.E.....
000001c: d3 46 0c 5c 22 59 f8 da 7b f8 18 14 8e 4b  .F.\"Y..{....K
000002a: 3a c1 9e 97 f8 f2 5c 18 21 63 13 c8 d3 86  :.....\.!c....
0000038: 45 8e 64 33 61 50 96 c4 48 ea 54 3b b3 ab  E.d3aP..H.T;..
0000046: bc 90 bc 24 21 20 50 30 85 5f 7d 7d 59 2c  ...$! P0._}}Y,
0000054: 4a 67 88 c8 94 29 1a 1a 1a 0f 38 c5 8a 49  Jg...)....8..I
0000062: 9b 54 90 b3 bd 23 c6 ed 26 ad b6 79 89 6f  .T...#..&..y.o
0000070: bd 2f 44 6c f5 3f ae af 62 9b 22 3d 69 40  ./Dl.?..b."=i@
000007e: 62 31 35 32 35 31 39 25 31 31 30 2a 2b 7d  b152519%110*+}

Cách tiếp cận này chia miền tên miền thành 110 bộ khác nhau và xác định hàm băm hơi khác nhau cho mỗi cặp.

Chấm điểm / xác minh

$ echo $LANG
en_US
$ cat gen.cjam
"qN%{_9b110%_"
[125 19 37 119 119 34 12 225 245 123 131 69 133 192 237 8 16 211 70 12 34 89 248 218 123 248 24 20 142 75 58 193 158 151 248 242 92 24 33 99 19 200 211 134 69 142 100 51 97 80 150 196 72 234 84 59 179 171 188 144 188 36 33 32 80 48 133 95 125 125 89 44 74 103 136 200 148 41 26 26 26 15 56 197 138 73 155 84 144 179 189 35 198 237 38 173 182 121 137 111 189 47 68 108 245 63 174 175 98 155]
:c`"=i@b152519%110*+}%N*N"
$ cjam gen.cjam > test.cjam
$ cjam test.cjam < british-english-huge.txt | sort -n > temp
$ head -1 temp
8
$ tail -1 temp
16776899
$ all=$(wc -l < british-english-huge.txt)
$ unique=$(uniq -u < temp | wc -l)
$ echo $[all - unique]
3677

Cổng sau tới Python có thể được sử dụng với đoạn ghi điểm chính thức:

h=lambda s,b:len(s)and ord(s[-1])+b*h(s[:-1],b)

def H(s):
 p=h(s,9)%110
 return h(s,ord(
  '}\x13%ww"\x0c\xe1\xf5{\x83E\x85\xc0\xed\x08\x10\xd3F\x0c"Y\xf8\xda{\xf8\x18\x14\x8eK:\xc1\x9e\x97\xf8\xf2\\\x18!c\x13\xc8\xd3\x86E\x8ed3aP\x96\xc4H\xeaT;\xb3\xab\xbc\x90\xbc$! P0\x85_}}Y,Jg\x88\xc8\x94)\x1a\x1a\x1a\x0f8\xc5\x8aI\x9bT\x90\xb3\xbd#\xc6\xed&\xad\xb6y\x89o\xbd/Dl\xf5?\xae\xafb\x9b'
  [p]))%152519*110+p

1
Tôi đã chuyển mã của mình sang Python để xác minh dễ dàng.
Dennis

Có phải htrong cổng Python đó tương ứng với một dựng sẵn của CJam?
kasperd

Đúng. Đó là CJam b(chuyển đổi cơ sở).
Dennis

Là quá trình ghi bàn của bạn trong bash?
GamrCorps

@GamrCorps Vâng, đó là Bash.
Dennis

11

Con trăn, 6446 6372


Giải pháp này đạt được số lần va chạm thấp hơn tất cả các mục trước đó và nó chỉ cần 44 trong số 140 byte được phép cho mã:

H=lambda s:int(s.encode('hex'),16)%16727401

2
@ mbomb007 đệ trình riêng của orlp %(2**24-1), vì vậy tôi nghĩ có thể tốt để yêu cầu làm rõ
Sp3000

12
@ mbomb007 Thử thách nói không có điều đó. Nó nói rằng hàm phải lấy một chuỗi ASCII làm đầu vào và đầu ra một số nguyên trong phạm vi đó. Bất kể đầu vào nào bạn cung cấp cho chức năng của tôi, đầu ra sẽ nằm trong phạm vi đó. Định nghĩa toán học của hàm từ không yêu cầu nó tạo ra mọi đầu ra được phép. Nếu đó là những gì bạn muốn thuật ngữ toán học bạn đang sử dụng là hàm tính toán. Nhưng từ tính từ không được sử dụng trong các yêu cầu.
kasperd

@ mbomb007: Không có yêu cầu nào cho hàm băm là tính từ. Ví dụ, nhiều hàm băm dựa trên địa chỉ bộ nhớ chỉ có thể tạo ra bội số của một số công suất nhỏ bằng 2 do căn chỉnh bộ nhớ, bao gồm cả hàm băm đối tượng mặc định trong các phiên bản cũ hơn của Python. Nhiều hàm băm thậm chí có một miền nhỏ hơn tên miền, vì vậy dù sao chúng cũng không thể bị từ chối.
user2357112

3
@ mbomb007 - Trong thực tế, do có xa hơn giá trị số từ [0, 2**24-1]hơn có từ trong ngôn ngữ tiếng Anh, nó sẽ là toán học không thể để thực hiện một băm nơi mỗi giá trị duy nhất trong phạm vi đó là có thể.
Darrel Hoffman

7

CJam, 6273

{49f^245b16777213%}

XOR mỗi ký tự với 49 , giảm chuỗi kết quả thông qua x, y ↦ 245x + y và lấy modulo dư 16.777.213 (số nguyên tố 24 bit lớn nhất).

Chấm điểm

$ cat hash.cjam
qN% {49f^245b16777213%} %N*N
$ all=$(wc -l < british-english-huge.txt)
$ unique=$(cjam hash.cjam < british-english-huge.txt | sort | uniq -u | wc -l)
$ echo $[all - unique]
6273

Tôi đã thực hiện lại thuật toán trong python từ mô tả của bạn. Tôi có thể xác nhận rằng điểm số của bạn kiểm tra với tính toán điểm chính thức.
kasperd

7

JavaScript (ES6), 6389

Hàm băm (105 byte):

s=>[...s.replace(/[A-Z]/g,a=>(b=a.toLowerCase())+b+b)].reduce((a,b)=>(a<<3)*28-a^b.charCodeAt(),0)<<8>>>8

Hàm tính điểm (NodeJS) (170 byte):

h={},c=0,l=require('fs').readFileSync(process.argv[2],'utf8').split('\n').map(a=>h[b=F(a)]=-~h[b])
for(w of Object.getOwnPropertyNames(h)){c+=h[w]>1&&h[w]}
console.log(c)

Gọi as node hash.js dictionary.txt, ở đâu hash.jslà tập lệnh, dictionary.txtlà tệp văn bản từ điển (không có dòng mới cuối cùng) và Fđược định nghĩa là hàm băm.

Cảm ơn Neil đã cạo 9 byte khỏi chức năng băm!


Tại sao giao cho a? Ngoài ra, thay vì ((...)>>>0)%(1<<24)bạn có thể có thể sử dụng (...)<<8>>>8.
Neil

@Neil Bởi vì bảng chữ cái, và tôi nhàm chán = P Ngoài ra, toán học bitwise đẹp! Điều đó đã lưu 7 byte =)
Mwr247

Điều tốt là đây không phải là mã golf, nếu không tôi cũng sẽ đưa bạn đến biến không sử dụng i.
Neil

@Neil Crap> _ <Tôi sử dụng điều đó trong khi thử nghiệm một số ý tưởng băm thay thế và quên xóa XD Có, điều tốt là đây không phải là một môn đánh gôn, mặc dù vậy, tôi rất thích nếu tôi có thể nén hàm băm và tính điểm vào cùng 140 byte, vì vậy mọi bit đều có ích;)
Mwr247

1
@ Sp3000 Gah, tôi hiểu ý của bạn. Của tôi không tính những cái ở đó ban đầu khi phát hiện va chạm. Tôi sẽ sửa nó.
Mwr247

5

Toán học, 6473

Bước tiếp theo ... thay vì tổng hợp các mã ký tự, chúng tôi coi chúng là các chữ số của một số cơ sở 151, trước khi lấy chúng theo modulo 2 24 .

hash[word_] := Mod[FromDigits[ToCharacterCode @ word, 151], 2^24]

Đây là một đoạn script ngắn để xác định số lượng va chạm:

Total[Last /@ DeleteCases[Tally[hash /@ words], {_, 1}]]

Tôi đã thử tất cả các căn cứ một cách có hệ thống từ đó 1trở đi, và cho đến nay căn cứ 151 mang lại ít va chạm nhất. Tôi sẽ cố gắng thêm một vài lần nữa để giảm điểm thêm một chút, nhưng bài kiểm tra hơi chậm.


5

Javascript (ES5), 6765

Đây là CRC24 được giảm xuống còn 140 Byte. Có thể chơi gôn nhiều hơn nhưng muốn có câu trả lời của tôi trong :)

function(s){c=0xb704ce;i=0;while(s[i]){c^=(s.charCodeAt(i++)&255)<<16;for(j=0;j++<8;){c<<=1;if(c&0x1000000)c^=0x1864cfb}}return c&0xffffff}

Trình xác thực trong node.js:

var col = new Array(16777215);
var n = 0;

var crc24_140 = 
function(s){c=0xb704ce;i=0;while(s[i]){c^=(s.charCodeAt(i++)&255)<<16;for(j=0;j++<8;){c<<=1;if(c&0x1000000)c^=0x1864cfb}}return c&0xffffff}

require('fs').readFileSync('./dict.txt','utf8').split('\n').map(function(s){ 
    var h = crc24_140(s);
    if (col[h]===1) {
        col[h]=2;
        n+=2;
    } else if (col[h]===2) {
        n++;
    } else {
        col[h]=1;
    }
});

console.log(n);

Chào mừng bạn đến với Câu đố lập trình & Code Golf!
Alex A.

... Và cảm ơn vì sự chào đón nồng nhiệt @AlexA.!
binarymax

5

Con trăn, 340053

Một số điểm khủng khiếp từ một thuật toán khủng khiếp, câu trả lời này tồn tại nhiều hơn để đưa ra một tập lệnh Python nhỏ hiển thị tính điểm.

H=lambda s:sum(map(ord, s))%(2**24)

Ghi bàn:

hashes = []
with open("british-english-huge.txt") as f:
    for line in f:
        word = line.rstrip("\n")
        hashes.append(H(word))

from collections import Counter
print(sum(v for k, v in Counter(hashes).items() if v > 1))

1
Có thể hữu ích khi có mã ghi điểm khẳng định rằng giá trị trả về từ hàm băm là một số nguyên trong phạm vi được phép.
kasperd

4

Trăn, 6390 6376 6359

H=lambda s:reduce(lambda a,x:a*178+ord(x),s,0)%(2**24-48)

Có thể được coi là một sửa đổi tầm thường cho câu trả lời của Martin Büttner .


3
@ mbomb007 Điều đó không đúng. Nếu chức năng của bạn luôn xuất ra 4 thì nó vẫn xuất ra trong phạm vi [0, 2**24-1]. Điều duy nhất không được phép là xuất ra bất kỳ số nào không nằm trong phạm vi đó, ví dụ -1hoặc 2**24.
orlp

3

Con trăn, 9310


Vâng, không phải là tốt nhất, nhưng ít nhất nó là một cái gì đó. Như chúng tôi nói trong tiền điện tử, không bao giờ viết hàm băm của riêng bạn .

Điều này cũng chính xác là 140 byte.

F=lambda x,o=ord,m=map:int((int(''.join(m(lambda z:str(o(z)^o(x[-x.find(z)])^o(x[o(z)%len(x)])),x)))^(sum(m(int,m(o,x))))^o(x[-1]))%(2**24))

2

Matlab, 30.828 8620 6848

Nó xây dựng hàm băm bằng cách gán một số nguyên tố cho mỗi tổ hợp ký tự / vị trí ascii và tính toán sản phẩm của họ cho mỗi từ modulo, số nguyên tố lớn nhất nhỏ hơn 2 ^ 24. Lưu ý rằng để kiểm tra, tôi đã chuyển cuộc gọi đến các số nguyên tố bên ngoài vào máy kiểm tra trực tiếp trước vòng lặp while và chuyển nó vào hàm băm, bởi vì nó đã tăng tốc lên khoảng 1000, nhưng phiên bản này hoạt động và độc lập. Nó có thể sụp đổ với các từ dài hơn khoảng 40 ký tự.

function h = H(s)
p = primes(1e6);
h = 1;
for i=1:length(s)
    h = mod(h*p(double(s(i))*i),16777213);
end
end

Kiểm thử:

clc
clear variables
close all

file = fopen('british-english-huge.txt');
hashes = containers.Map('KeyType','uint64','ValueType','uint64');

words = 0;
p = primes(1e6);
while ~feof(file)
    words = words + 1;
    word = fgetl(file);
    hash = H(word,p);
    if hashes.isKey(hash)
        hashes(hash) = hashes(hash) + 1;
    else
        hashes(hash) = 1;
    end
end

collisions = 0;
for key=keys(hashes)

    if hashes(key{1})>1
        collisions = collisions + hashes(key{1});
    end
end

Nếu bạn muốn tiết kiệm không gian trong chương trình của mình, bạn không cần phải chuyển đổi char của mình thành doublerõ ràng. Ngoài ra, bạn có thể sử dụng numelchứ không phải length. Không chắc chắn những gì bạn làm với tất cả các byte thêm!
Suever

1

Ruby, 9309 va chạm, 107 byte

def hash(s);require'prime';p=Prime.first(70);(0...s.size).reduce(0){|a,i|a+=p[i]**(s[i].ord)}%(2**24-1);end 

Không phải là một ứng cử viên tốt, nhưng tôi muốn khám phá một ý tưởng khác với các mục khác.

Gán n số nguyên tố đầu tiên cho n vị trí đầu tiên của chuỗi, sau đó tổng tất cả số nguyên tố [i] ** (mã ascii của chuỗi [i]), sau đó mod 2 ** 24-1.


1

Java 8, 7054 6467

Điều này được lấy cảm hứng từ (nhưng không được sao chép từ) hàm java.lang.String.hashCode dựng sẵn, vì vậy hãy thoải mái không cho phép theo quy tắc # 2.

w -> { return w.chars().reduce(53, (acc, c) -> Math.abs(acc * 79 + c)) % 16777216; };

Ghi bàn:

import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

public class TweetableHash {
    public static void main(String[] args) throws Exception {
        List<String> words = Files.readAllLines(Paths.get("british-english-huge.txt"));

        Function<String, Integer> hashFunc = w -> { return w.chars().reduce(53, (acc, c) -> Math.abs(acc * 79 + c)) % 16777216; };

        Map<Integer, Integer> hashes = new HashMap<>();
        for (String word : words) {
            int hash = hashFunc.apply(word);
            if (hash < 0 || hash >= 16777216) {
                throw new Exception("hash too long for word: " + word + " hash: " + hash);
            }

            Integer numOccurences = hashes.get(hash);
            if (numOccurences == null) {
                numOccurences = 0;
            }
            numOccurences++;

            hashes.put(hash, numOccurences);
        }

        int numCollisions = hashes.values().stream().filter(i -> i > 1).reduce(Integer::sum).get();
        System.out.println("num collisions: " + numCollisions);
    }
}

@muddyfish bạn có thể kiểm tra phiên bản hiện tại không? Tôi nghĩ rằng tôi đã chiếm 3 lần va chạm và vẫn nhận được kết quả tương tự.
Bewusstsein

Điều này không giải thích cho va chạm ba chiều. Nếu bạn thay thế hashesbằng Map<Integer, Integer> hashes = new HashMap<>()và sau đó đếm số lượng từ cho mỗi hàm băm, bạn có thể tính đến chúng một cách chính xác.
Peter Taylor

Điểm của bạn vẫn không chính xác. Tôi nghĩ để tính toán một số điểm chính xác, bạn phải xuất numHashes + numCollutions. (Mà tôi đoán sẽ đưa bạn đến gần với ước tính 6832 của tôi cho một lời sấm ngẫu nhiên.)
kasperd

Sửa đổi các phần chấm điểm thành này: pastebin.com/nLeg4qut
TheNumberOne

yeah, đã sửa lỗi phân loại và có vẻ như một giá trị hợp lý hơn nhiều bây giờ, ty
Bewusstsein

1

Con trăn, 6995 6862 6732

Chỉ là một chức năng RSA đơn giản. Khá khập khiễng, nhưng đánh bại một số câu trả lời.

M=0x5437b3a3b1
P=0x65204c34d
def H(s):
    n=0
    for i in range(len(s)):
        n+=pow(ord(s[i]),P,M)<<i
    return n%(8**8)

1

C ++: 7112 6694 6483 6479 6412 6339 va chạm, 90 byte

Tôi đã thực hiện một thuật toán di truyền ngây thơ cho mảng hệ số của tôi. Tôi sẽ cập nhật mã này khi nó tìm thấy mã tốt hơn. :)

int h(const char*s){uint32_t t=0,p=0;while(*s)t="cJ~Z]q"[p++%6]*t+*s++;return t%16777213;}

Chức năng kiểm tra:

int main(void)
{
    std::map<int, int> shared;

    std::string s;
    while (std::cin >> s) {
        shared[h(s.c_str())]++;
    }

    int count = 0;
    for (auto c : shared) {
        if ((c.first & 0xFFFFFF) != c.first) { std::cerr << "invalid hash: " << c.first << std::endl; }
        if (c.second > 1) { count += c.second; }
    }

    std::cout << count << std::endl;
    return 0;
}

1

C #, 6251 6335

int H(String s){int h = 733;foreach (char c in s){h = (h * 533 + c);}return h & 0xFFFFFF;}

Các hằng số 533 và 733 889 và 155 cho điểm cao nhất trong số tất cả những cái tôi đã tìm kiếm cho đến nay.


1

tcl

88 byte, 6448/3233 va chạm

Tôi thấy mọi người đã đếm số lượng từ va chạm, hoặc nếu không thì số lượng từ được đặt trong các thùng không trống. Tôi đưa ra cả hai tính - thứ nhất là theo đặc điểm kỹ thuật của vấn đề, và thứ hai là những gì nhiều áp phích đã được báo cáo.

# 88 bytes, 6448 collisions, 3233 words in nonempty buckets

puts "[string length {proc H w {incr h;lmap c [split $w {}] {set h [expr (2551*$h+[scan $c %c])%2**24]};set h}}] bytes"

proc H w {incr h;lmap c [split $w {}] {set h [expr (2551*$h+[scan $c %c])%2**24]};set h}

# change 2551 above to:
#   7: 85 bytes, 25839 colliding words, 13876 words in nonempty buckets
#   97: 86 bytes, 6541 colliding words, 3283 words in nonempty buckets
#   829: 87 bytes, 6471 colliding words, 3251 words in nonempty buckets


# validation program

set f [open ~/Downloads/british-english-huge.txt r]
set words [split [read $f] \n]
close $f

set have {};                        # dictionary whose keys are hash codes seen
foreach w $words {
    if {$w eq {}} continue
    set h [H $w]
    dict incr have $h
}
set coll 0
dict for {- count} $have {
    if {$count > 1} {
        incr coll $count
    }
}
puts "found $coll collisions"

2
Bạn thấy câu trả lời ở đâu khi sử dụng phương pháp không chính xác để tính điểm? Đã có rất nhiều, nhưng tất cả chúng đều được sửa hoặc xóa từ nhiều năm trước. Tôi thấy bốn câu trả lời còn lại với điểm dưới 6000 vì bốn câu trả lời đó thực sự đã được tối ưu hóa để có điểm thấp như vậy.
kasperd

1
Theo như tôi có thể nói, mã của bạn là proc H w {incr h;lmap c [split $w {}] {set h [expr (2551*$h+[scan $c %c])%2**24]};set h}... đúng không?
Erik the Outgolfer

@EriktheOutgolfer: Vâng, đúng vậy
sergiol

1
Tôi thứ hai @kasperd: Bạn có thể chỉ ra câu trả lời nào không hạch toán các va chạm theo thông số kỹ thuật không? Bạn đã thực sự cố gắng để chạy chúng?
sergiol

1

Python 3, 89 byte, 6534 va chạm băm

def H(x):
 v=846811
 for y in x:
  v=(972023*v+330032^ord(y))%2**24
 return v%2**24

Tất cả những con số ma thuật lớn mà bạn thấy ở đây là hằng số mờ.


1

JavaScript, 121 byte, va chạm 3268 3250 3244 6354 (3185)

s=>{v=i=0;[...s].map(z=>{v=((((v*13)+(s.length-i)*7809064+i*380886)/2)^(z.charCodeAt(0)*266324))&16777215;i++});return v}

Các tham số (13, 7809064, 380886, 2, 266324) là do thử nghiệm và lỗi.

Tôi vẫn tối ưu hóa, và vẫn còn chỗ để thêm các tham số bổ sung, làm việc để tối ưu hóa hơn nữa ...

xác minh

hashlist = [];
conflictlist = [];
for (x = 0; x < britain.length; x++) {
    hash = h(britain[x]);                      //britain is the 340725-entry array
    hashlist.push(hash);
}

conflict = 0; now_result = -1;
(sortedlist = sort(hashlist)).map(v => {
    if (v == now_result) {
        conflict++;
        conflictlist.push(v);
    }
    else
        now_result = v;
});

console.log(conflictlist);

var k = 0;
while (k < conflictlist.length) {
    if (k < conflictlist.length - 1 && conflictlist[k] == conflictlist[k+1])
        conflictlist.splice(k,1);
    else
        k++;
}

console.log(conflict + " " + (conflict+conflictlist.length));

3268> 3250 - Thay đổi tham số thứ 3 từ 380713 thành 380560.

3250> 3244 - Thay đổi tham số thứ 3 từ 380560 thành 380886.

3244> 6354 - Đã thay đổi tham số thứ 2 từ 7809143 thành 7809064 và nhận thấy tôi đã sử dụng phương pháp tính toán sai; P


1

Dưới đây là một vài cấu trúc tương tự, khá "có thể gieo hạt" và có thể tối ưu hóa tham số gia tăng. Chết tiệt thật khó để lấy dưới 6k! Giả sử điểm số có giá trị trung bình là 6829 và std là 118, tôi cũng đã tính toán khả năng nhận được điểm thấp như vậy một cách ngẫu nhiên.

Clojure A, 6019, Pr = 1: 299,5e9

 #(reduce(fn[r i](mod(+(* r 811)i)16777213))(map *(cycle(map int"~:XrBaXYOt3'tH-x^W?-5r:c+l*#*-dtR7WYxr(CZ,R6J7=~vk"))(map int %)))

Clojure B, 6021, Pr = 1: 266.0e9

#(reduce(fn[r i](mod(+(* r 263)i)16777213))(map *(cycle(map int"i@%(J|IXt3&R5K'XOoa+Qk})w<!w[|3MJyZ!=HGzowQlN"))(map int %)(rest(range))))

Clojure C, 6148, Pr = 1: 254.0e6

#(reduce(fn[r i](mod(+(* r 23)i)16777213))(map *(cycle(map int"ZtabAR%H|-KrykQn{]u9f:F}v#OI^so3$x54z2&gwX<S~"))(for[c %](bit-xor(int c)3))))

Clojure, 6431, Pr = 1: 2.69e3 (có gì đó khác biệt)

#(mod(reduce bit-xor(map(fn[i[a b c]](bit-shift-left(* a b)(mod(+ i b c)19)))(range)(partition 3 1(map int(str"w"%"m")))))16776869)

Đây là hàm băm ad-hoc ban đầu của tôi, nó có bốn tham số có thể điều chỉnh.


Thủ thuật cho điểm thấp là hằng số chuỗi trong đó mỗi ký tự có thể được tối ưu hóa độc lập mà không làm hỏng tối ưu hóa bạn đã thực hiện cho các ký tự khác.
kasperd

Vâng, trước tiên tôi đã thử tối ưu hóa cho các chuỗi ngắn hơn, vì việc thêm nhiều ký tự vào chuỗi "entropy" không ảnh hưởng đến các chuỗi đó (một khi hệ số nhân rđược cố định). Tuy nhiên, thuật toán tìm kiếm của tôi về cơ bản là sức mạnh vũ phu, và tôi không chắc liệu sự lựa chọn ban đầu của hệ số nhân rcó quan trọng hay không.
NikoNyrh

Có lẽ chỉ cần nhân các giá trị ASCII không mang lại đủ entropy cho trò chơi. Nhiều thuật toán chấm điểm tốt dường như có hình thức f(n) % (8^8 - g(n)).
NikoNyrh

Có một câu trả lời giải thích làm thế nào nó đạt mức thấp nhất là 3677. Những câu hỏi thậm chí còn thấp hơn mức đó có ít lời giải thích.
kasperd

0

Ruby, 6473 va chạm, 129 byte

h=->(w){@p=@p||(2..999).select{|i|(2..i**0.5).select{|j|i%j==0}==[]};c=w.chars.reduce(1){|a,s|(a*@p[s.ord%92]+179)%((1<<24)-3)}}

Biến @p được điền với tất cả các số nguyên tố dưới 999.

Điều này chuyển đổi giá trị ascii thành số nguyên tố và lấy modulo sản phẩm của chúng thành số nguyên tố lớn. Yếu tố mờ nhạt của 179 liên quan đến thực tế là thuật toán ban đầu được sử dụng để tìm đảo chữ, trong đó tất cả các từ được sắp xếp lại của cùng một chữ cái có cùng hàm băm. Bằng cách thêm yếu tố trong vòng lặp, nó làm cho đảo chữ có mã riêng biệt.

Tôi có thể loại bỏ ** 0,5 (kiểm tra sqrt cho số nguyên tố) với chi phí hiệu năng kém hơn để rút ngắn mã. Tôi thậm chí có thể làm cho trình tìm số nguyên tố thực thi trong vòng lặp để loại bỏ thêm chín ký tự, để lại 115 byte.

Để kiểm tra, phần sau đây cố gắng tìm giá trị tốt nhất cho hệ số fudge trong phạm vi từ 1 đến 300. Giả sử rằng tệp từ trong thư mục / tmp:

h=->(w,y){
  @p=@p||(2..999).
    select{|i|(2..i**0.5). 
    select{|j|i%j==0}==[]};
  c=w.chars.reduce(1){|a,s|(a*@p[s.ord%92]+y)%((1<<24)-3)}
}

american_dictionary = "/usr/share/dict/words"
british_dictionary = "/tmp/british-english-huge.txt"
words = (IO.readlines british_dictionary).map{|word| word.chomp}.uniq
wordcount = words.size

fewest_collisions = 9999
(1..300).each do |y|
  whash = Hash.new(0)
  words.each do |w|
    code=h.call(w,y)
    whash[code] += 1
  end
  hashcount = whash.size
  collisions = whash.values.select{|count| count > 1}.inject(:+)
  if (collisions < fewest_collisions)
    puts "y = #{y}. #{collisions} Collisions. #{wordcount} Unique words. #{hashcount} Unique hash values"
    fewest_collisions = collisions
  end
end

1
Điểm số có vẻ đáng ngờ. Bạn có chắc là bạn đang đếm tất cả các từ va chạm? Một số câu trả lời trước đó chỉ đếm nhầm một từ cho mỗi giá trị băm va chạm.
kasperd

Bạn có thể đúng. Tôi phải xem xét cách tôi đếm và xem nó có giống với định nghĩa của bạn không. Tôi đang đếm xem có bao nhiêu từ và trừ đi bao nhiêu mã băm duy nhất được tạo ra. Nếu các từ A và B có cùng mã băm, thì đó là một hoặc hai va chạm? Tôi đếm nó là một.
Paul Chernoch

1
Tôi đã không xác định chức năng cho điểm. Tôi chỉ sao chép nó từ câu trả lời mẫu được đăng bởi cùng một người dùng đã đăng thử thách. Hầu hết các câu trả lời đều có điểm nằm trong khoảng từ 6273 đến 6848. Đã có nhiều câu trả lời mỗi câu mắc cùng một lỗi trong tính toán điểm dẫn đến việc tính toán một số điểm xấp xỉ một nửa so với mức cần có. (Chính xác một nửa số điểm chính xác nếu không có trường hợp nào có ba từ va chạm.)
kasperd

1
Vâng, tôi đã phạm sai lầm tương tự. Tôi sẽ sửa đổi câu trả lời của tôi sau. Phải bắt một chiếc xe buýt.
Paul Chernoch

Đã sửa lỗi ghi bàn.
Paul Chernoch

0

tcl

# 91 byte, 6508 va chạm

91 byte, 6502 va chạm

proc H s {lmap c [split $s ""] {incr h [expr [scan $c %c]*875**[incr i]]};expr $h&0xFFFFFF}

Máy tính vẫn đang thực hiện tìm kiếm để đánh giá xem có giá trị nào gây ra ít va chạm hơn so với cơ sở 147 875 hay không, vẫn là máy ghi âm.

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.