Tweetable karma fonksiyon zorluğu


73

Bu 140 bayt 1 veya daha az kaynak kodunda bir karma işlevi yazacaksınız . Karma işlevi giriş olarak bir ASCII stringi almalı ve çıkış olarak 24 bit işaretsiz tamsayı ([0, 2 24 -1]) döndürmelidir .

Bu büyük İngiliz İngilizcesi 2 sözlükteki her kelime için karma işleviniz değerlendirilecektir . Puanınız, karma değeri başka bir kelimeyle (çarpışma) paylaşan kelimelerin miktarıdır.

En düşük puan kazanır, ilk poster tarafından kırılan bağlar.

Test durumu

Göndermeden önce, lütfen puanlama komut dosyanızı aşağıdaki girişte test edin:

duplicate
duplicate
duplicate
duplicate

4'ten başka bir puan verirse, buggy olur.


Açıklama kuralları:

  1. Karma işleviniz, bir dizinin tamamı değil tek bir dizgede çalışmalıdır. Ayrıca, karma işleviniz giriş dizgisi ve çıktı tamsayısından başka bir G / Ç yapamayabilir.
  2. Yerleşik karma işlevleri veya benzer işlevler (örneğin, karıştırılan baytlara şifreleme) izin verilmez.
  3. Karma işleviniz deterministic olmalıdır.
  4. Diğer yarışmaların aksine, puanlama girdisi için özellikle optimizasyona izin verilir.

1 Twitter'ın bayt yerine karakterleri sınırladığını biliyorum, ancak basitlik için bu bayt için sınırlama olarak baytları kullanacağız.
2 Debian's wbritish-huge'den ASCII olmayan kelimeleri kaldırarak değiştirildi.


11
Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch's? Ne ...?
Luis Mendo

8
@DonMuesli en.wikipedia.org/wiki/Llanfairpwllgwyngyll (eğlenceli gerçek: bu kelime aynı zamanda Jelly'in dahili sıkıştırma sözlüğünde de bulunur)
Martin Ender

8
Yerleşik sözlüklere izin vermemelisin.
Dennis,

4
Başvuru için: SHA-512'nin 24 MSB'sini almak 6816 puanını alacaktır.
Dennis

10
Bazı zarf arkası hesaplamaları: D=340275Kelimeler ve R=2^24karma çıktılarda rastgele bir karma D^2/(2*R) = 3450, bazıları çakışan beklenen bir çarpışma çiftine sahiptir . Beklenen bir D^3/(6*R^2) = 23çarpışan üçlü ve önemsiz sayıda daha büyük çarpışma vardır, bu üçlülerin muhtemelen birbirinden ayrı olduğu anlamına gelir. Bu, üçlü, geri kalanını çiftler halinde 6829, karma değeri paylaşan beklenen bir sözcük verir 70. Standart sapma olarak tahmin edilir 118, bu nedenle <6200rastgele bir karma ile elde kabaca 5 sigma olayıdır.
xnor

Yanıtlar:


11

Tamam, ben gidip bir golf dili öğreneceğim.

CJam, 140 bayt, 3314 kelime çarpışan

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#)%}

Bir blok tanımlar (anonim işlev). Test qN%%N*Netmek için, stdin'deki newline ayrılmış sözcük listesini almak ve stdout'ta newline ayrılmış karma listesi yazabilirsiniz. Eşdeğer Python kodu:

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 bayt, 3535 3396 kelime çarpışan

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

Adlı bir işlevi tanımlar y. Test jmyd.zetmek için, stdin'deki newline ayrılmış sözcük listesini almak ve stdout'ta newline ayrılmış karma listesi yazabilirsiniz. Eşdeğer Python kodu:

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]))

Teorik sınırlar

Ne kadar iyi yapmayı umabiliriz? Burada bir x grafiği, çarpışan sözcük sayısı, y'ye karşılık, bayt cinsinden entropi, en fazla x çarpışan sözcük elde etmek için gerekli. Örneğin, nokta (2835, 140) bize rastgele bir fonksiyonun en fazla 2835 olasılıkla 1/256 ** 140 kelimesiyle çarpıştığını söylemektedir, bu yüzden 140 ile bundan daha iyisini yapmamız son derece düşüktür. kod baytları.

graph


Teorik limitlerin güzel analizi. Bu teorik sınırı aşmak için, muhtemelen söz konusu sözlük için optimize edilmiş yerleşik fonksiyonlara sahip bir dil kullanmak zorunda kalacaksınız (hile olacaktır). Dilin yerleşik bir şifreleme karma değeri varsa, sınırlama, en uygun çözümü bulmak için az çok yapıcı bir yönteme dönüştürülebilir. Bunu göz önünde bulundurun: $ h (w || c)% 2 ^ {24} $ burada $ c $ bir bayt dizesi sabitidir. Rastgele bir kehanet modelinde yüksek olasılıkla optimum seviyeye yaklaşıldığı gösterilebilir. Tabii ki, $ c $ zorlamak brüt mümkün olmazdı.
kasperd

Grafiğin formülünü nasıl hesapladınız? Gerçekten ilginç!
NikoNyrh

@NikoNyrh Dinamik programlama. (Olsun w , c , h olan bir durumu temsil) ağırlık olan bir deyişle, C çarpışma edilir h farklı karma ve kalan w - c tüm farklı karma sahiptir. Bir rastgele bir kelime eklemek, durum haline gelir ( w + 1, c , h olasılığı 1) - ( h + ağırlık - c / 2 ^ 24, ya da () w + 1, c + 1, h olasılığı ile birlikte) h / 2 ^ 24 veya ( w + 1, c+ 2, h+ 1) olasılıkla ( w - c ) / 2 ^ 24. Daha sonra, x çarpışan kelimelerle işaretlenmiş son entropi , cx ile eyaletlerdeki (340275, c , h ) olasılıkların toplamının 1 / 256'sındaki log tabanıdır .
Anders Kaseorg

Kimsenin karma fonksiyonunu nasıl bulduğunuzu sormadığına inanamıyorum? Bilmek çok isterim.
Anush

22

Python, 5333 4991

Bunun rastgele bir kahinten çok daha iyi puan alan ilk yarışmacının olduğuna inanıyorum.

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
Büyücülük! def H(s):n=int(s.encode('hex'),16);return n%...Bir şekilde kullanabilmeniz durumunda, 5 bayt kaydeder ...
Dennis

3
@Dennis Dize 5 byte daha uzun sabit yapmak için 5 byte kullanabilirdim. Fakat uzunluğu değiştirirsem, dizgiyi sabit sıfırdan oluşturmaya başlamalıyım. Ve bu 5 baytın bana ipi oluşturmaya başlamaya değecek kadar gelişme sağlayacağından emin değilim. Dize sabitini optimize etmek için saatler harcadım.
kasperd

@Dennis Birkaç fazladan bayt, sürekli kaçmaya ihtiyaç duyan bazı karakterleri kullanma özgürlüğümü verir. Bu şekilde, dizgiyi tekrar inşa etmek zorunda kalmadan birkaç ekstra byte kullanabilirim.
kasperd

7
Başka bir bayt istiyorsanız 2**24 == 8**8,.
Anders Kaseorg

20

Python 2, 140 bayt, 4266 çarpışan kelimeler

Belirsiz güvenilirliklerine rağmen yazdırılamayan baytlarla başlamak istemedim, ama pek başlamadım. :-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 yazdırılabilir bayt, 4662 4471 4362 kelime çarpışması

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]))

Açıkça kasperd'in çözümünün şeklinden esinlenilmiş, ancak modül alanı üzerindeki afin dönüşümünün ve tamamen farklı parametrelerin önemli bir şekilde eklenmesiyle.


+1 Kavga etmeden vazgeçmiyorum. Fakat mevcut çözümümü optimize etmeyi bırakıp başka bir yaklaşım bulmam gerektiğini düşünüyorum, çünkü parametrelerimi optimize etmek için mevcut yaklaşımımı kullanmaya devam edersem sizi yenmeyeceğim. Ben
kendiminkini dövdüğümde çözümümde

@ kasperd: Başar, devam et. :-P
Anders Kaseorg 7

1
@AndersKaseorg Dizeyi nasıl buluyorsunuz?
ASCII-sadece

@AndersKaseorg Parametre aramamı çok hızlandırmayı başardım. Ve aramamın yetersiz çözümler üzerinde sıkışmasına neden olan bir engeli kaldırdım. Ama yine de 4885'ten daha iyi olamadım. Neden daha fazla yapamayacağımı biraz düşündükten sonra, çözümümün neyin yanlış olduğunu ve nasıl düzeltilebileceğini aniden farkettim. Şimdi çözümünüzdeki afin dönüşümü bana çok mantıklı geliyor. Sanırım yakalayabileceğim tek yol, kendime afin bir dönüşüm kullanmak.
kasperd

1
@ kasperd: Çok hoş. n%(8**8-ord('…'[n%70]))Diğer parametre değişiklikleri olmadan daha iyi bir dize ararken sadece 4995'e ulaşmayı başardım, bu yüzden yeni optimize ediciniz benimkine yetişmiş gibi görünüyor. Şimdi bu daha ilginç hale geliyor!
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*+}

Bu yaklaşım etki alanını ve etki alanını ayırır 110 ayrık kümeye her çift için biraz farklı bir karma işlevi tanımlar.

Puanlama / Doğrulama

$ 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

Python'a ait olan aşağıdaki liman, resmi puanlama snippet'iyle kullanılabilir:

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
Kolayca doğrulama için kodumu Python'a taşıdım.
Dennis,

Does ho Python limanda bir CJam yerleşiğini gelmektedir?
kasperd

Evet. CJam's b(temel dönüşüm).
Dennis,

Puanlama sürecin bash olarak mı?
GamrCorps

@GamrCorps Evet, bu Bash.
Dennis,

11

Python, 6446 6372


Bu çözüm önceki tüm girdilerden daha düşük çarpışma sayısı elde eder ve kod için izin verilen 140 bayttan yalnızca 44'üne ihtiyaç duyar:

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

2
@ mbomb007 orlp'in kendi bildirimi var %(2**24-1), bu yüzden açıklama isteyip istemediğini düşünüyorum
Sp3000

12
@ mbomb007 Mücadelesi böyle bir şey söylemez. İşlevin bir ASCII dizesini girdi olarak alması ve bu aralıkta bir tamsayı çıkarması gerektiğini söylüyor. Fonksiyonuma hangi girişi verdiğinize bakılmaksızın, çıkış o aralıkta olacaktır. Sözcük fonksiyonunun matematiksel tanımı izin verilen her çıktının üretilmesini gerektirmez. Eğer kullanmak istediğin matematiksel terim buysa, surektif fonksiyondu. Ancak surjective kelimesi gereksinimlerde kullanılmamıştır.
kasperd

@ mbomb007: Karma işlevlerin denetleyici olma zorunluluğu yoktur. Örneğin, birçok bellek adresi tabanlı karma işlevi, Python'un eski sürümlerinde varsayılan nesne karma değeri de dahil olmak üzere, bellek hizalaması nedeniyle yalnızca 2 küçük gücün katlarının çoğunu üretebilir. Çoğu karma işlevi, alan adından bile daha küçük bir etki alanına sahiptir, bu nedenle herhangi bir şekilde denetleyici olamazlardı.
user2357112

3
@ mbomb007 - Aslında, İngilizcede olduğundan çok daha fazla sayıda değer verildiği için, bu aralıktaki her bir değerin mümkün olduğu yerlerde karma yapmak [0, 2**24-1]matematiksel olarak imkansız olurdu .
Darrel Hoffman,

7

CJam, 6273

{49f^245b16777213%}

XOR ile her karakter 49 , ile elde edilen dizi azaltmak x, y ↦ 245x + y , ve tortu, modüle almak 16.777.213 (en büyük 24 bit ana).

puanlama

$ 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

Python'daki algoritmayı tanımından tekrar uyguladım. Puanının resmi puan hesaplamasından geçtiğini onaylayabilirim.
kasperd

7

JavaScript (ES6), 6389

Karma işlevi (105 bayt):

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

Puanlama işlevi (NodeJS) (170 bayt):

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)

Olarak Çağrı node hash.js dictionary.txtnerede hash.js, script edilir dictionary.txt(son yeni satır olmadan) sözlük metin dosyası olduğunu veF karma işlevi olarak tanımlanır.

Karma işlevi kapalı 9 byte tıraş için Neil teşekkür ederiz!


Neden atama? Ayrıca, ((...)>>>0)%(1<<24)muhtemelen yerine kullanabilirsiniz (...)<<8>>>8.
Neil

@Neil Çünkü alfabe ve ben sıkıcıyım = P Ayrıca, bitsel güzel eşleme! Bu 7 bayt kurtardı =)
Mwr247

İyi ki bu kod golf değil, yoksa kullanılmayan değişken için de seni kullanmak zorunda kalacağım i.
Neil

@Neil Crap> _ <Bazı alternatif karma fikirleri test ederken ve XD'yi kaldırmayı unuttuğumda kullanıyorum Evet, iyi, bu bir golf değil, yine de, eğer hash ve puanlama işlevlerini sıkıştırabilirsem çok isterdim aynı 140 bayt içine, bu yüzden her bit yardımcı olur;)
Mwr247

1
@ Sp3000 Gah, ne demek istediğini anlıyorum. Mine, çarpışma bulunduğunda başlangıçta oradakileri saymıyor. Bunu düzelteceğim.
Mwr247,

5

Mathematica, 6473

Bir sonraki adım ... karakter kodlarını toplamak yerine, bunları modulo 2 24 almadan önce bir temel 151 sayısının basamağı olarak kabul ediyoruz .

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

İşte çarpışma sayısını belirlemek için kısa bir betik:

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

Tüm üsleri sistematik olarak daha 1sonra denedim ve bugüne kadar üs 151 en az çarpışmaya yol açtı. Skoru biraz daha aşağı çekmek için birkaç tane daha deneyeceğim, ancak testler biraz yavaş.


5

Javascript (ES5), 6765

Bu CRC24 140 Byte'a kadar tıraş edildi. Golf daha fazla olabilir ama cevabımı almak istedim :)

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}

Node.js konumundaki Validator:

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);

Programlama Bulmacaları ve Kod Golf'üne Hoşgeldiniz!
Alex A. 19:

... Ve sıcak bir karşılama için teşekkürler @AlexA.!
binarymax

5

Python, 340053

Korkunç bir algoritmadan korkunç bir puan alan bu cevap, puanlamayı gösteren küçük bir Python komut dosyası vermek için daha fazla var.

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

Skor yapmak:

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
Puanlama kodunun karma işlevinden dönüş değerinin izin verilen aralıktaki bir tam sayı olduğunu iddia etmesi faydalı olabilir.
kasperd

4

Python, 6390 6376 6359

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

Martin Büttner'ın cevabında önemsiz bir değişiklik olarak kabul edilebilir .


3
@ mbomb007 Bu doğru değil. Eğer fonksiyonunuz her zaman 4 çıkış veriyorsa, hala aralıkta çıkış yapıyordur [0, 2**24-1]. İzin verilmeyen tek şey, bu aralığın içinde olmayan herhangi bir sayıyı çıkarmaktır, örneğin -1veya 2**24.
orlp

3

Python, 9310


Evet, en iyisi değil, ama en azından bir şey. Kriptoda söylediğimiz gibi, asla kendi karma işlevinizi yazmayın .

Bu tam olarak 140 byte uzunluğunda.

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, 30828 8620 6848

Her ascii karakter / pozisyon combo'suna bir asal sayı atayarak ve 2 ^ 24'ten küçük en büyük asal olan her bir kelime modülü için ürünlerini hesaplayarak karma oluşturur. Test için çağrıyı, prime doğrudan döngüden önce test cihazının dışına taşıdığımı ve hash fonksiyonuna geçirdiğimi, çünkü yaklaşık 1000 faktör kadar hızlandırdığını, ancak bu versiyonun çalıştığını ve kendi kendine yeten olduğunu not edin. Yaklaşık 40 karakterden uzun kelimelerle çökebilir.

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

Tester:

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

Programınızda yer kazanmak istiyorsanız, karakterinizi doubleaçıkça dönüştürmeniz gerekmez . Ayrıca numelyerine kullanabilirsiniz length. Yine de tüm bu ekstra baytlarla ne yapacağınızdan emin değilsiniz!
Suever

1

Ruby, 9309 çarpışma, 107 bayt

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 

İyi bir yarışmacı değil, ama diğer kayıtlardan farklı bir fikir keşfetmek istedim.

İlk n primayı dizenin ilk n konumuna atayın, sonra tüm asal [i] ** ([[]] dizinin ascii kodu), sonra mod 2 ** 24-1'i toplayın.


1

Java 8, 7054 6467

Bu, yerleşik java.lang.String.hashCode işlevinden ilham alır (ancak kopyalanmaz), bu nedenle kural 2'ye göre izin vermeyin.

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

Skor yapmak:

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 geçerli sürümünü kontrol eder misiniz? 3 yollu çarpışmaları hesaba kattığımı ve hala aynı sonucu aldığımı düşünüyorum.
Bewusstsein

Bu üç yollu çarpışmaları hesaba katmaz. Eğer değiştirirseniz hashesile Map<Integer, Integer> hashes = new HashMap<>()ve daha sonra her karma için kelimelerin sayısını, doğru onlar için açıklama getirebilir.
Peter Taylor

Puanın hala yanlış görünüyor. Doğru bir puan hesaplayabileceğinizi düşünüyorum, numHashes + numCollisions çıktısı almalısınız. (Sanırım rastgele bir kahin için 6832 tahminime
yaklaşacağım

Not verme bölümlerini buna göre değiştirin: pastebin.com/nLeg4qut
TheNumberOne

evet, puanlamayı düzeltti ve şimdi çok daha makul bir değere benziyor, ty
Bewusstsein

1

Python, 6995 6862 6732

Sadece basit bir RSA işlevi. Oldukça topal, ama bazı cevaplar atıyor.

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, 90 bayt çarpışma

Katsayı dizim için saf bir genetik algoritma uyguladım. Daha iyi olanları bulduğunda bu kodu güncelleyeceğim. :)

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

Test işlevi:

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;}

533 ve 733 889 ve 155 sabitleri , şu ana kadar aradıklarımın hepsinden en iyi puanı veriyor.


1

tcl

88 bayt, 6448/3233 çarpışma

İnsanların çarpışan kelimelerin sayısını ya da boş olmayan kovalara yerleştirilen kelimelerin sayısını saydığını gördüm. Her iki sayıyı da veriyorum - ilki sorun belirtimine göre, ikincisi daha fazla posterin rapor ettiği şey.

# 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
Skoru hesaplamak için yanlış yöntemi kullanarak cevapları nerede görüyorsunuz? Çok şey oldu ama hepsi yıllar önce düzeltildi veya silindi. 6000'den düşük puanlarla kalan dört cevap görüyorum, çünkü bu dört cevap aslında düşük puanlara sahip olacak şekilde optimize edildi.
kasperd

1
Söyleyebileceğim kadarıyla, kodun proc H w {incr h;lmap c [split $w {}] {set h [expr (2551*$h+[scan $c %c])%2**24]};set h}... doğru mu?
Outgolfer Erik,

@EriktheOutgolfer: Evet, öyle
sergiol

1
Ben ikinci @ kasperd: Hangi cevapların çarpışmalara soru özelliğine göre hesaplanmadığını işaret edebilir misiniz? Gerçekten onları çalıştırmayı denedin mi?
sergiol

1

Python 3, 89 bayt, 6534 karma çarpışma

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

Burada gördüğünüz tüm büyük sayılar, geçiştirme sabitleridir.


1

JavaScript, 121 bayt, 3268 3250 3244 6354 (3185) çarpışma

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}

Parametreler (13, 7809064, 380886, 2, 266324) deneme yanılmadır.

Hala optimize edilebilir bence ve hala daha fazla optimizasyon için çalışmak için ekstra parametreler eklemek için yer var ...

Doğrulama

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 - 3. parametreyi 380713'ten 380560'a değiştirdi.

3250> 3244 - 3. parametreyi 380560'tan 380886'ya değiştirdi.

3244> 6354 - 2. parametreyi 7809143'ten 7809064'e değiştirdi ve yanlış hesaplama yöntemini kullandığımı fark ettim; P


1

Burada oldukça "görülebilir" olan ve artımlı parametre optimizasyonunu mümkün kılan benzer yapılar bulunmaktadır. Kahretsin 6k'dan daha düşük olması zor! Skorun 6829 ve 118'in ortalaması olduğunu varsayarak, bu kadar düşük puanları rastgele alma ihtimalini de hesapladım.

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 (farklı bir şey)

#(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)

Bu benim orijinal geçici hash fonksiyonumdu, dört ayarlanabilir parametreye sahipti.


Düşük bir puanın püf noktası, diğer karakterler için yaptığınız optimizasyonu bozmadan her karakterin bağımsız olarak optimize edilebileceği bir dize sabitidir.
kasperd

Evet, ilk önce sadece daha kısa dizeler için optimizasyon yapmaya çalıştım, çünkü "entropy" dizgisine daha fazla karakter eklemek bunları etkilemiyor (çarpanı rdüzeltildikten sonra). Ancak yine de arama algoritmam temelde kaba bir güçtür ve çarpanın ilk seçiminin rönemli olup olmadığından emin değilim .
NikoNyrh

Belki sadece ASCII değerlerini çarpmak oyuna yeterince entropi getirmez. Pek çok iyi puanlama algoritması bu forma sahip gibi görünüyor f(n) % (8^8 - g(n)).
NikoNyrh

3677'ye nasıl düştüğünü açıklayan bir cevap var. Bundan daha düşük puan alanların çok az açıklaması var.
kasperd

0

Ruby, 6473 çarpışma, 129 bayt

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)}}

P değişkeni 999'un altındaki tüm primerler ile doldurulur.

Bu, ascii değerlerini asal sayılara dönüştürür ve ürünlerinin modülünü büyük bir asal sayıya getirir. 179'un geçiştirici faktörü, orijinal algoritmanın, aynı harflerin yeniden düzenlenmesi olan tüm kelimelerin aynı karmayı elde ettiği anagramların bulunmasında kullanım için olduğu gerçeğiyle ilgilidir. Döngüdeki faktörü ekleyerek, anagramların farklı kodlara sahip olmasını sağlar.

** Kısaltmak için düşük performans pahasına ** 0.5 (üssü için sqrt testi) kaldırabilir. Başbakan sayı bulucusunun dokuz karakter daha kaldırarak 115 bayt bırakarak döngüde çalışmasını bile sağlayabilirim.

Test etmek için, aşağıdakiler 1 ila 300 aralığında fudge faktörü için en iyi değeri bulmaya çalışır. / Tmp dizininde bulunan word dosyasının:

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
Skor şüpheli görünüyor. Tüm çarpışan kelimeleri saydığına emin misin? Birkaç önceki cevap yanlışlıkla her bir çarpışan karma değer için sadece bir kelimeyi sayıyordu.
kasperd

Haklı olabilirsin. Nasıl saydığımı düşünmeli ve bunun sizin tanımınızla aynı olup olmadığını görmeliyim. Ne kadar kelime olduğunu sayıyorum ve kaç tane benzersiz karma kod üretildiğini çıkartıyorum. A ve B sözcükleri aynı hashcode'u alırsa, bu bir veya iki çarpışma mıdır? Bir olarak sayıyorum.
Paul Chernoch

1
Puanlama işlevini tanımlamamıştım. Ben sadece soruyu gönderen aynı kullanıcı tarafından gönderilen örnek cevaptan kopyaladım. Cevapların çoğu, 6273 ile 6848 arasında değişen puanlara sahiptir. Skor hesaplamasında, her birinin olması gereken puanın yarısını hesaplamak için aynı hatayı yapan birçok cevap vardır. (Üç çarpışan kelimeden oluşan bir durum yoksa, doğru puanın yarısı kadardır.)
kasperd

1
Evet, aynı hatayı yaptım. Cevabımı daha sonra değiştireceğim. Bir otobüse binmeliyim.
Paul Chernoch

Puanlama düzeltildi.
Paul Chernoch

0

tcl

# 91 bayt, 6508 çarpışma

91 bayt, 6502 çarpışma

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

Bilgisayar hala kayıt yapan 147 875 üssünden daha az çarpışmaya neden olan bir değer olup olmadığını değerlendirmek için bir arama yapıyor .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.