Ne kadar yükseğe gidebilirsin? (Bir kodlama + algoritmalar mücadelesi)


34

Şimdi herkes , Python'un gerçekte ne kadar yavaş olduğu için (genellikle şaşırtıcı) düşük seviye kodlama uzmanlığını geliştirdi. (Ya da diliniz ne kadar hızlı?) Ve Python Gerçekten Ne Kadar Yavaş? (Bölüm II)?Bir algoritmayı geliştirme yeteneğinizi de uzatacak olan bir meydan okuma zamanı.

Aşağıdaki kod 9 uzunluğunun bir listesini hesaplar. Listedeki konum , iç çarpımlar arasında hesaplanırken ien az iardışık sıfırların bulunma sayısını sayar.F veS . Tam olarak bunu yapmak için, mümkün olan tüm listelerin üzerinde dolaşır Fuzunluğu nve listeler Suzunluğu n+m-1.

#!/usr/bin/python
import itertools
import operator

n=8
m=n+1
leadingzerocounts = [0]*m
for S in itertools.product([-1,1], repeat = n+m-1):
    for F in itertools.product([-1,1], repeat = n):
        i = 0
        while (i<m and sum(map(operator.mul, F, S[i:i+n])) == 0):
            leadingzerocounts[i] +=1
            i+=1
print leadingzerocounts

Çıktı

[4587520, 1254400, 347648, 95488, 27264, 9536, 4512, 2128, 1064].

Bu kodu kullanarak n'yi 10,12,14,16,18,20'ye yükseltirseniz, çok hızlı bir şekilde çok yavaş olur.

kurallar

  • Buradaki zorluk mümkün olduğu kadar büyük ve n için doğru çıktıyı vermektir. Sadece n değerleri bile geçerlidir.
  • Bir beraberlik varsa, galibiyet en büyük n için makinemdeki en hızlı koda gider.
  • 10 dakikadan fazla süren kodu test etme hakkını saklı tutarım.
  • Algoritmayı, doğru çıktı verdiği sürece istediğiniz şekilde değiştirebilirsiniz. Aslında zorunda kalacaksın kazanma yolunda iyi bir ilerleme kaydetmek için algoritmayı değiştirmek .
  • Kazanan, soru belirlendikten bir hafta sonra verilecek.
  • Ödül, kazananın ne zaman kazanılacağına kısa bir süre sonra geleceği zaman verilecektir.

Benim makine zamanlamaları benim makinede işletilecek. Bu, AMD FX-8350 Sekiz Çekirdekli İşlemciye standart bir ubuntu kurulumudur. Bu ayrıca kodunuzu çalıştırabilmem gerektiği anlamına geliyor. Sonuç olarak, yalnızca kolayca erişilebilen ücretsiz yazılımı kullanın ve lütfen kodunuzu nasıl derleyeceğiniz ve çalıştıracağınızla ilgili tüm talimatları ekleyin.

Durum .

  • C . @Fors tarafından 49 saniyede n = 12
  • Java . n = 16, 03:07 (@ PeterTaylor)
  • C ++ . @ilmale tarafından 2:21 içinde n = 16
  • Rpython . n = 22, 03:11 (@primo)
  • Java . n: 22: 06: 56'da @ PeterTaylor
  • Nimrod . @ReimerBehrends tarafından 9:28 saniyede n = 24

Kazanan, Nimrod'da bir girişle Reimer Behrends oldu!

Bir kontrol olarak, n = 22 çıktısının olması gerekir [12410090985684467712, 2087229562810269696, 351473149499408384, 59178309967151104, 9975110458933248, 1682628717576192, 284866824372224, 48558946385920, 8416739196928, 1518499004416, 301448822784, 71620493312, 22100246528, 8676573184, 3897278464, 1860960256, 911646720, 451520512, 224785920, 112198656, 56062720, 28031360, 14015680].


Yarışma bitti ama ... Puanım tükenene kadar n'2 (bilgisayarımdaki 10 dakika içinde) ile artan her gönderim için 200 puan sunacağım . Bu teklif sonsuza dek açık .


1
"Birkaç dakikadan fazla süren kodu test etme hakkını saklı tutuyorum." > Makineniz üzerinde tam olarak bir zaman belirtmelisiniz, aksi takdirde bu soruda objektif bir kriter yoktur.
pastebin.com 0mr8spkT'yi

14
Ben seviyorum bu "benim hızını artırmak" zorlukları. Bunlarla ticari bir ürün inşa ediyorsanız, bir cehennem hızlı bir ürüne sahip olacaksınız ve ayrıca kötü bir dehasınız .
Rainbolt

1
Belki de daha bilgilendirici bir başlık buna dikkat çeker mi?
TheDoctor,

8
Bu tür bir mücadeleyi sürdürmeye devam edersek, en azından ilginç kılmak için farklı bir problemi çözmeye çalışmamız gerektiğini düşünüyorum (ek özelliklerde aynı problemde bir değişiklik değil).
grovesNL

2
@Claudiu, işlemcisinin 8 fiziksel çekirdeğine sahip, ancak alma / kod çözme ve FPU birimleri çekirdekler arasında paylaşılıyor. Darboğaz bu alanlardan birinde olduğunda, daha çok dörtlü gibi davranır. Tamsayı mantığını kötüye kullanmak ve büyük kod boyutlarından kaçınmak, 8 çekirdekli gibidir.
Stefan

Yanıtlar:


20

Nimrod (N = 22)

import math, locks

const
  N = 20
  M = N + 1
  FSize = (1 shl N)
  FMax = FSize - 1
  SStep = 1 shl (N-1)
  numThreads = 16

type
  ZeroCounter = array[0..M-1, int]
  ComputeThread = TThread[int]

var
  leadingZeros: ZeroCounter
  lock: TLock
  innerProductTable: array[0..FMax, int8]

proc initInnerProductTable =
  for i in 0..FMax:
    innerProductTable[i] = int8(countBits32(int32(i)) - N div 2)

initInnerProductTable()

proc zeroInnerProduct(i: int): bool =
  innerProductTable[i] == 0

proc search2(lz: var ZeroCounter, s, f, i: int) =
  if zeroInnerProduct(s xor f) and i < M:
    lz[i] += 1 shl (M - i - 1)
    search2(lz, (s shr 1) + 0, f, i+1)
    search2(lz, (s shr 1) + SStep, f, i+1)

when defined(gcc):
  const
    unrollDepth = 1
else:
  const
    unrollDepth = 4

template search(lz: var ZeroCounter, s, f, i: int) =
  when i < unrollDepth:
    if zeroInnerProduct(s xor f) and i < M:
      lz[i] += 1 shl (M - i - 1)
      search(lz, (s shr 1) + 0, f, i+1)
      search(lz, (s shr 1) + SStep, f, i+1)
  else:
    search2(lz, s, f, i)

proc worker(base: int) {.thread.} =
  var lz: ZeroCounter
  for f in countup(base, FMax div 2, numThreads):
    for s in 0..FMax:
      search(lz, s, f, 0)
  acquire(lock)
  for i in 0..M-1:
    leadingZeros[i] += lz[i]*2
  release(lock)

proc main =
  var threads: array[numThreads, ComputeThread]
  for i in 0 .. numThreads-1:
    createThread(threads[i], worker, i)
  for i in 0 .. numThreads-1:
    joinThread(threads[i])

initLock(lock)
main()
echo(@leadingZeros)

İle derleyin

nimrod cc --threads:on -d:release count.nim

(Nimrod indirilebilir burada .)

Bu, n = 20 için ayrılan süre içinde çalışır (ve yalnızca tek bir iplik kullanıldığında, ikinci durumda yaklaşık 2 dakika süren n = 18 için).

Algoritma, sıfır olmayan bir iç ürünle karşılaşıldığında arama ağacını budayan, yinelemeli bir arama kullanır. Ayrıca, herhangi bir vektör çifti için, (F, -F)sadece bir tane düşünmemiz gerektiğini, diğerinin de aynı iç ürün setlerini ürettiğini göz ardı ederek, arama alanını yarı yarıya azalttık.S aynı zamanda ) .

Uygulama, özyinelemeli aramanın ilk birkaç seviyesini açmak / sıralamak için Nimrod'un metaprogramlama tesislerini kullanıyor. Bu, Nimrod'un arka ucu olarak gcc 4.8 ve 4.9 kullanırken ve clang için makul miktarda kullanıldığında biraz zaman kazandırır.

Sadece F seçimimizden ilk N konumunda eşit sayıdaki S değerlerini göz önünde bulundurmamız gerektiğini gözlemleyerek araştırma alanı daha da budanabilir. Ancak bunun karmaşıklığı veya hafızasının ihtiyaçları büyük değerler için ölçeklendirilmez N, bu durumlarda döngü gövdesinin tamamen atlandığı göz önüne alındığında.

İç ürünün sıfır olduğu yerin yeniden düzenlenmesi, döngüdeki herhangi bir bit sayma işlevini kullanmaktan daha hızlı görünmektedir. Görünüşe göre masaya erişim oldukça iyi bir konuma sahiptir.

Özyinelemeli aramanın nasıl yürüdüğünü göz önünde bulundurarak, problemin dinamik programlamaya uygun olması gerektiği gibi görünüyor, ancak bunu makul miktarda bellekle yapmanın belirgin bir yolu yok.

Örnek çıktılar:

N = 16:

@[55276229099520, 10855179878400, 2137070108672, 420578918400, 83074121728, 16540581888, 3394347008, 739659776, 183838720, 57447424, 23398912, 10749184, 5223040, 2584896, 1291424, 645200, 322600]

N = 18:

@[3341140958904320, 619683355033600, 115151552380928, 21392898654208, 3982886961152, 744128512000, 141108051968, 27588886528, 5800263680, 1408761856, 438001664, 174358528, 78848000, 38050816, 18762752, 9346816, 4666496, 2333248, 1166624]

N = 20:

@[203141370301382656, 35792910586740736, 6316057966936064, 1114358247587840, 196906665902080, 34848574013440, 6211866460160, 1125329141760, 213330821120, 44175523840, 11014471680, 3520839680, 1431592960, 655872000, 317675520, 156820480, 78077440, 39005440, 19501440, 9750080, 4875040]

Algoritmayı diğer uygulamalarla karşılaştırmak amacıyla, N = 16 makinemde tek bir iplik kullanırken yaklaşık 7.9 saniye ve dört çekirdek kullanırken 2.3 saniye sürer.

N = 22, Nimrod'un arka ucu olarak gcc 4.4.6 olan 64 çekirdekli bir makinede yaklaşık 15 dakika sürer ve 64-bit tam sayıların içine taşar leadingZeros[0](muhtemelen işaretsiz olanlar da bakmaz).


Güncelleme: Birkaç iyileştirme için yer buldum. İlk olarak, belirli bir değer için F, karşılık gelen Svektörlerin ilk 16 girişini tam olarak numaralandırabiliriz , çünkü tam olarak farklı N/2yerlerde olmaları gerekir . Biz boyutta bit vektörlerin listesi precompute Yani Nsahip N/2bit seti ve baştarafını türetmek için bunları kullanabilir Sdan F.

İkincisi, özyinelemeli aramada değerini her zaman bildiğimizi gözlemleyerek iyileştirebiliriz F[N](çünkü MSB bit gösteriminde sıfırdır). Bu, iç üründen hangi dalda tutunduğumuzu kesin olarak tahmin etmemizi sağlar. Bu aslında tüm araştırmayı özyinelemeli bir döngüye dönüştürmemize izin verirken, bu aslında şube tahminini biraz parçaladı, bu yüzden en üst seviyeyi orijinal biçiminde tutuyoruz. Öncelikle yaptığımız dallanma miktarını azaltarak hala zaman kazanıyoruz.

Bazı temizleme işlemleri için kod şimdi işaretsiz tamsayılar kullanıyor ve bunları 64 bit'te düzeltiyor (sadece birinin bunu 32 bit mimaride çalıştırmak istemesi durumunda).

Genel hızlanma, x3 ve x4 faktörü arasındadır. N = 22'nin 10 dakikadan daha az bir sürede çalışması için sekizden fazla çekirdeğe ihtiyacı var, ancak 64 çekirdekli bir makinede şu anda yaklaşık dört dakikaya düştü ( numThreadsbuna göre çarpıldı). Yine de, farklı bir algoritma olmadan iyileştirme için daha fazla yer olduğunu sanmıyorum.

N = 22:

@[12410090985684467712, 2087229562810269696, 351473149499408384, 59178309967151104, 9975110458933248, 1682628717576192, 284866824372224, 48558946385920, 8416739196928, 1518499004416, 301448822784, 71620493312, 22100246528, 8676573184, 3897278464, 1860960256, 911646720, 451520512, 224785920, 112198656, 56062720, 28031360, 14015680]

Yeniden düzenlendi, arama alanındaki daha fazla azaltma kullanıldı. Quadcore makinemde N = 22 için 9:49 dakika içinde çalışır.

Son güncelleme (sanırım). F seçimleri için daha iyi denklik sınıfları, çalışma zamanını N = 22 için 3:19 dakikaya kadar kesme süresi 57 saniye (düzenleme: Yanlışlıkla sadece bir iplik ile çalıştırdım) makinemde.

Bu değişiklik, bir vektörün döndürülerek diğerine dönüştürülebilmesi durumunda aynı baştaki sıfırları üretmesi gerçeğinden yararlanır. Ne yazık ki, oldukça kritik bir düşük seviye optimizasyonu, bit gösteriminde F'nin üst bitinin her zaman aynı olmasını gerektirir ve bu denklik kullanılırken, arama alanını bir miktar kısalttı ve çalışma süresini farklı bir durum alanı kullanarak yaklaşık dörtte bir oranında azaltın F üzerinde azalma, ek yükün düşük seviyeli optimizasyonu ortadan kaldırmaktan daha fazla mahsup etmesi. Bununla birlikte, bu sorunun, birbirinin tersi olan F'nin de eşdeğer olduğu gerçeği göz önüne alınarak giderilebileceği ortaya çıkmıştır. Bu, denklik sınıflarının hesaplanmasının karmaşıklığına biraz eklenirken, aynı zamanda yukarıda belirtilen düşük seviye optimizasyonunu sürdürmeme izin verdi, bu da yaklaşık x3'lük bir hızlanmaya yol açtı.

Birikmiş veriler için 128 bit tamsayıları destekleyen bir güncelleme daha. 128 bitlik tamsayılar ile derlemek için, gerekir longint.nimdan burada ve birlikte derlemek için -d:use128bit. N = 24 hala 10 dakikadan fazla sürüyor, ancak ilgilenenler için aşağıdaki sonucu ekledim.

N = 24:

@[761152247121980686336, 122682715414070296576, 19793870419291799552, 3193295704340561920, 515628872377565184, 83289931274780672, 13484616786640896, 2191103969198080, 359662314586112, 60521536552960, 10893677035520, 2293940617216, 631498735616, 230983794688, 102068682752, 48748969984, 23993655296, 11932487680, 5955725312, 2975736832, 1487591936, 743737600, 371864192, 185931328, 92965664]

import math, locks, unsigned

when defined(use128bit):
  import longint
else:
  type int128 = uint64 # Fallback on unsupported architectures
  template toInt128(x: expr): expr = uint64(x)

const
  N = 22
  M = N + 1
  FSize = (1 shl N)
  FMax = FSize - 1
  SStep = 1 shl (N-1)
  numThreads = 16

type
  ZeroCounter = array[0..M-1, uint64]
  ZeroCounterLong = array[0..M-1, int128]
  ComputeThread = TThread[int]
  Pair = tuple[value, weight: int32]

var
  leadingZeros: ZeroCounterLong
  lock: TLock
  innerProductTable: array[0..FMax, int8]
  zeroInnerProductList = newSeq[int32]()
  equiv: array[0..FMax, int32]
  fTable = newSeq[Pair]()

proc initInnerProductTables =
  for i in 0..FMax:
    innerProductTable[i] = int8(countBits32(int32(i)) - N div 2)
    if innerProductTable[i] == 0:
      if (i and 1) == 0:
        add(zeroInnerProductList, int32(i))

initInnerProductTables()

proc ror1(x: int): int {.inline.} =
  ((x shr 1) or (x shl (N-1))) and FMax

proc initEquivClasses =
  add(fTable, (0'i32, 1'i32))
  for i in 1..FMax:
    var r = i
    var found = false
    block loop:
      for j in 0..N-1:
        for m in [0, FMax]:
          if equiv[r xor m] != 0:
            fTable[equiv[r xor m]-1].weight += 1
            found = true
            break loop
        r = ror1(r)
    if not found:
      equiv[i] = int32(len(fTable)+1)
      add(fTable, (int32(i), 1'i32))

initEquivClasses()

when defined(gcc):
  const unrollDepth = 4
else:
  const unrollDepth = 4

proc search2(lz: var ZeroCounter, s0, f, w: int) =
  var s = s0
  for i in unrollDepth..M-1:
    lz[i] = lz[i] + uint64(w)
    s = s shr 1
    case innerProductTable[s xor f]
    of 0:
      # s = s + 0
    of -1:
      s = s + SStep
    else:
      return

template search(lz: var ZeroCounter, s, f, w, i: int) =
  when i < unrollDepth:
    lz[i] = lz[i] + uint64(w)
    if i < M-1:
      let s2 = s shr 1
      case innerProductTable[s2 xor f]
      of 0:
        search(lz, s2 + 0, f, w, i+1)
      of -1:
        search(lz, s2 + SStep, f, w, i+1)
      else:
        discard
  else:
    search2(lz, s, f, w)

proc worker(base: int) {.thread.} =
  var lz: ZeroCounter
  for fi in countup(base, len(fTable)-1, numThreads):
    let (fp, w) = fTable[fi]
    let f = if (fp and (FSize div 2)) == 0: fp else: fp xor FMax
    for sp in zeroInnerProductList:
      let s = f xor sp
      search(lz, s, f, w, 0)
  acquire(lock)
  for i in 0..M-1:
    let t = lz[i].toInt128 shl (M-i).toInt128
    leadingZeros[i] = leadingZeros[i] + t
  release(lock)

proc main =
  var threads: array[numThreads, ComputeThread]
  for i in 0 .. numThreads-1:
    createThread(threads[i], worker, i)
  for i in 0 .. numThreads-1:
    joinThread(threads[i])

initLock(lock)
main()
echo(@leadingZeros)

N = 22 ile elde edilen sonuç 12410090985684467712'dir ve 63.42 bit alır ve bu nedenle işaretsiz bir 64 bit'e uyar.
Stefan,

2
Barı kesinlikle çok etkileyici bir şekilde yükselttiniz.

1
Nimrod'u kullanan birini görmek güzel. :)
cjfaure

@Stefan Belki kodlama sihirbazınız N = 22 için bu metodu 10 dakikanın altında bulabilir mi?

Birkaç saat sonra sonlanan N = 22 denedim. O [bana verir Ancak -6036653088025083904, 2087229562810269696, 351473149499408384, 59178309967151104, 9975110458933248, 1682628717576192, 284866824372224, 48558946385920, 8416739196928, 1518499004416, 301448822784, 71620493312, 22100246528, 8676573184, 3897278464, 1860960256, 911646720, 451520512, 224785920, 112198656, 56062720, 28031360, 14015680] bu bir taşma hatası gibi görünüyor. Nimrod biliyorum ama bunu çözmek için imzasız girdiler kullanmak mümkün mü?

11

Java ( n=22?)

Bence n=16buna benzer bir yaklaşım kullanmaktan daha iyi cevapların çoğunun, sömürdüğü simetrilerde ve görevi iş parçacığı arasında bölme biçiminde farklılık göstermelerine rağmen bence .

Soruda tanımlanan vektörler, bit dizeleriyle ve XORing ile üst üste binen pencerenin iç ürünü ve tam olarak n/2ayarlanmış bitlerin (ve dolayısıyla n/2bitlerin temizlendiğini) olup olmadığını kontrol ederek değiştirilebilir . Orada n! / ((n/2)!)(merkezi binom katsayısı) dizeleri nile bit n/2(ararım set bit dengeli dizeleri) bu yüzden herhangi bir için, Fo pencerelerin çokluğu dikkat çeker Ssıfır iç ürünü vermek hangi. Ayrıca, bir Sboyunca kayma hareketi ve sıfır bir iç ürün veren gelen bir bit bulup bulamayacağımızı kontrol etme, düğümleri pencereleri olan ve kenarları ubir düğümü vilk bitleri olan bir düğüme bağlayan bir grafikte kenar aramaya karşılık gelir arasında .n-1 bitleri sonuncularn-1u

Örneğin, n=6ve F=001001bu grafiği alıyoruz:

F = 001001 için grafik

ve F=001011biz bu grafiği almak için :

F = 001011 için grafik

Sonra her biri için saymak gerekir idan 0kadar nkaç yolları uzunluğu iher için grafikler üzerinde toplayarak vardır F. Bence çoğumuz derinlik ilk arama kullanıyoruz.

Grafiklerin seyrek olduğuna dikkat edin: Her bir düğümün en fazla 1 derece ve en fazla bir derece derecesinde olduğunu kanıtlamak kolaydır. Bu da mümkün olan tek yapının basit zincirler ve basit döngüler olduğu anlamına gelir. Bu, DFS'yi biraz kolaylaştırır.

Birkaç simetriden faydalanırım: Dengeli dizeler bit tersi ( ~ALGOL ailesinden birçok dilde işlem) altında ve bit dönmesi altında kapalıdır , bu yüzden değerleri Fbu işlemlerle ilgili olan gruplandırabiliriz ve sadece DFS yaparız bir Zamanlar.

public class CodeGolf26459v8D implements Runnable {
    private static final int NUM_THREADS = 8;

    public static void main(String[] args) {
        v8D(22);
    }

    private static void v8D(int n) {
        int[] bk = new int[1 << n];
        int off = 0;
        for (int i = 0; i < bk.length; i++) {
            bk[i] = Integer.bitCount(i) == n/2 ? off++ : -1;
        }

        int[] fwd = new int[off];
        for (int i = 0; i < bk.length; i++) {
            if (bk[i] >= 0) fwd[bk[i]] = i;
        }

        CodeGolf26459v8D[] runners = new CodeGolf26459v8D[NUM_THREADS];
        Thread[] threads = new Thread[runners.length];
        for (int i = 0; i < runners.length; i++) {
            runners[i] = new CodeGolf26459v8D(n, i, runners.length, bk, fwd);
            threads[i] = new Thread(runners[i]);
            threads[i].start();
        }

        try {
            for (int i = 0; i < threads.length; i++) threads[i].join();
        }
        catch (InterruptedException ie) {
            throw new RuntimeException("This shouldn't be reachable", ie);
        }

        long surviving = ((long)fwd.length) << (n - 1);
        for (int i = 0; i <= n; i++) {
            for (CodeGolf26459v8D runner : runners) surviving -= runner.survival[i];
            System.out.print(i == 0 ? "[" : ", ");
            java.math.BigInteger result = new java.math.BigInteger(Long.toString(surviving));
            System.out.print(result.shiftLeft(n + 1 - i));
        }
        System.out.println("]");
    }

    public final int n;
    protected final int id;
    protected final int numRunners;
    private final int[] bk;
    private final int[] fwd;

    public long[] survival;

    public CodeGolf26459v8D(int n, int id, int numRunners, int[] bk, int[] fwd) {
        this.n = n;
        this.id = id;
        this.numRunners = numRunners;

        this.bk = bk;
        this.fwd = fwd;
    }

    private int dfs2(int[] graphShape, int flip, int i) {
        if (graphShape[i] != 0) return graphShape[i];

        int succ = flip ^ (fwd[i] << 1);
        if (succ >= bk.length) succ ^= bk.length + 1;

        int j = bk[succ];
        if (j == -1) return graphShape[i] = 1;

        graphShape[i] = n + 1; // To detect cycles
        return graphShape[i] = dfs2(graphShape, flip, j) + 1;
    }

    @Override
    public void run() {
        int n = this.n;
        int[] bk = this.bk;
        int[] fwd = this.fwd;

        // NB The initial count is approx 2^(2n - 1.33 - 0.5 lg n)
        // For n=18 we overflow 32-bit
        // 64-bit is good up to n=32.
        long[] survival = new long[n + 1];
        boolean[] visited = new boolean[1 << (n - 1)];
        int th = 0;
        for (int f = 0; f < visited.length; f++) {
            if (visited[f]) continue;

            int m = 1, g = f;
            while (true) {
                visited[g] = true;
                int ng = g << 1;
                if ((ng >> (n - 1)) != 0) ng ^= (1 << n) - 1;
                if (ng == f) break;
                m++;
                g = ng;
            }

            if (th++ % numRunners != id) continue;

            int[] graphShape = new int[fwd.length];
            int flip = (f << 1) ^ f;
            for (int i = 0; i < graphShape.length; i++) {
                int life = dfs2(graphShape, flip, i);
                if (life <= n) survival[life] += m;
            }
        }

        this.survival = survival;
    }
}

2.5GHz Core 2'de alıyorum

# n=18
$ javac CodeGolf26459v8D.java && time java CodeGolf26459v8D
[3341140958904320, 619683355033600, 115151552380928, 21392898654208, 3982886961152, 744128512000, 141108051968, 27588886528, 5800263680, 1408761856, 438001664, 174358528, 78848000, 38050816, 18762752, 9346816, 4666496, 2333248, 1166624]

real    0m3.131s
user    0m10.133s
sys     0m0.380s

# n=20
$ javac CodeGolf26459v8D.java && time java CodeGolf26459v8D
[203141370301382656, 35792910586740736, 6316057966936064, 1114358247587840, 196906665902080, 34848574013440, 6211866460160, 1125329141760, 213330821120, 44175523840, 11014471680, 3520839680, 1431592960, 655872000, 317675520, 156820480, 78077440, 39005440, 19501440, 9750080, 4875040]

real    1m8.706s
user    4m20.980s
sys     0m0.564s

# n=22
$ javac CodeGolf26459v8D.java && time java CodeGolf26459v8D
[12410090985684467712, 2087229562810269696, 351473149499408384, 59178309967151104, 9975110458933248, 1682628717576192, 284866824372224, 48558946385920, 8416739196928, 1518499004416, 301448822784, 71620493312, 22100246528, 8676573184, 3897278464, 1860960256, 911646720, 451520512, 224785920, 112198656, 56062720, 28031360, 14015680]

real    20m10.654s
user    76m53.880s
sys     0m6.852s

Lembik'in bilgisayarının 8 çekirdeği olduğundan ve daha önceki tek iş parçacıklı programımı benimkinden iki kat daha hızlı çalıştırdığı için n=22, 8 dakikadan daha az bir sürede çalışacağı konusunda iyimserim .


07:17! Çok hoş. Yöntemi biraz daha açıklar mısın lütfen?

6

C

Temel olarak, söz konusu algoritmanın sadece biraz optimize edilmiş bir uygulamasıdır. Bu n=12süre içinde yönetebilir .

#include <stdio.h>
#include <inttypes.h>

#define n 12
#define m (n + 1)

int main() {
    int i;
    uint64_t S, F, o[m] = {0};
    for (S = 0; S < (1LLU << (n + m - 1)); S += 2)
        for (F = 0; F < (1 << (n - 1)); F++)
            for (i = 0; i < m; i++)
                if (__builtin_popcount(((S >> i) & ((1 << n) - 1)) ^ F) == n >> 1)
                    o[i] += 4;
                else
                    break;
    for (i = 0; i < m; i++)
        printf("%" PRIu64 " ", o[i]);
    return 0;
}

n=12Derleme dahil test çalıştırması :

$ clang -O3 -march=native -fstrict-aliasing -ftree-vectorize -Wall fast.c
$ time ./a.out 
15502147584 3497066496 792854528 179535872 41181184 9826304 2603008 883712 381952 177920 85504 42560 21280 
real    0m53.266s
user    0m53.042s
sys     0m0.068s
$

Yorum: Beynimi açtım ve ilk değerin her zaman olacağını hesaplamak için bazı basit kombinatorikler kullandım n! / ((n / 2)!)^2 * 2^(n + m - 1). Bana öyle geliyor ki bu soruna tamamen cebirsel bir çözüm olması gerekiyor.


Bunu derlerken çok uyarı alırım. Gcc -Wall -Wextra Fors.c -o Fors'u deneyin

Daha önceki bir yinelemeden unutulmuş bir kaç kullanılmayan değişken vardı, ama bunları kaldırdım, en azından birkaç uyarı ortadan kalkmalıydı. Şu anda GCC'im yok (yalnızca Clang) ve Clang bana şu anda herhangi bir uyarı vermiyor (kullanılmayan değişkenleri kaldırdıktan sonra). Ve Clang, genellikle uyarılar söz konusu olduğunda daha katı olduğundan, şunu söylemeliyim ki, herhangi bir uyarı aldığınıza biraz şaşırdım.
Fors

Fors.c: 13: 17: warning: '&' [-Mparentheses] (iki kez) operasındaki '-' etrafına parantez önermek ve iki kez işaretlemek ve ayrıca uyarı: '% llu' biçiminde 'uzun uzun imzasız int türünü argümanı beklemekten şikayetçi. ', ancak argüman 2' uint64_t '[-Wformat =] tipine sahip. Aslında clang da benim için printf ifadesinden şikayet ediyor,

Son değişikliklerle GCC hiçbir uyarı mesajı atmamalıdır.
Fors

Hala Fors.c: 13: 49: warning: '^' [-Wparentheses] operandında aritmetik parantez önermektedir. Ancak daha kötü bir haber için makinemde 10 dakikadan uzun sürüyor.

5

Java, n=16

Herhangi bir belirli değeri için Forada \binom{n}{n/2}onunla sıfır iç çarpımı olan vektörler. Böylece, köşeleri eşleşen vektörler olan ve kenarları kaymaya karşılık gelen bir grafik oluşturabiliriz S, ve sonra ngrafiğe kadar uzunluktaki yolları saymamız gerekir .

Koşulları bitsel işlemlerle değiştirerek mikroişlemeyi denemedim, ancak nçalışma süresinin her iki katı artışı yaklaşık 16 kat artar, bu nedenle eşiğe yakın olmadığım sürece bu yeterli bir fark yaratmaz. Makinemde değilim.

public class CodeGolf26459 {

    public static void main(String[] args) {
        v3(16);
    }

    // Order of 2^(2n-1) * n ops
    private static void v3(int n) {
        long[] counts = new long[n+1];
        int mask = (1 << n) - 1;
        for (int f = 0; f < (1 << (n-1)); f++) {
            // Find adjacencies
            long[] subcounts = new long[1 << n];
            for (int g = 0; g < (1 << n); g++) {
                subcounts[g] = Integer.bitCount(f ^ g) == n/2 ? 2 : -1;
            }

            for (int round = 0; round <= n; round++) {
                long count = 0;
                // Extend one bit.
                long[] next = new long[1 << n];
                for (int i = 0; i < (1 << n); i++) {
                    long s = subcounts[i];
                    if (s == -1) next[i] = -1;
                    else {
                        count += s;
                        int j = (i << 1) & mask;
                        if (subcounts[j] >= 0) next[j] += s;
                        if (subcounts[j + 1] >= 0) next[j + 1] += s;
                    }
                }
                counts[round] += count << (n - round);
                subcounts = next;
            }
        }

        System.out.print("[");
        for (long count : counts) System.out.print(count+", ");
        System.out.println("]");
    }
}

2.5GHz Core 2'de alıyorum

$ javac CodeGolf26459.java && time java -server CodeGolf26459 
[55276229099520, 10855179878400, 2137070108672, 420578918400, 83074121728, 16540581888, 3394347008, 739659776, 183838720, 57447424, 23398912, 10749184, 5223040, 2584896, 1291424, 645200, 322600, ]

real    6m2.663s
user    6m4.631s
sys     0m1.580s

Sırtıma göre şu an kendi çözümümü uygulamak istemiyorum. Her tepe noktasının en fazla bir halefi vardır, bu nedenle diziye gerçekten ihtiyacınız yoktur. fKöşelerin kombinasyonları ve başlangıç ​​noktaları üzerinde verimli bir şekilde yineleme f_xor_gyapmak için tam olarak n/2ayarlanmış bitlerle her şeyi yineleyin . Bunların her biri için, hepsinin üzerinde yineleyin fve alın g = f ^ f_xor_g.
David Eisenstat

@David, biliyorum ve sürüm 7, Atom netbook'umda bir dakikada n = 18 yapıyor, ancak tatilden geri dönene kadar gönderemiyorum.
Peter Taylor

4

RPython, N = 22 ~ 3: 23

Çok dişli, istifsiz özyinelemeli bir iniş kullanarak. Program iki komut satırı argümanı kabul eder: N ve çalışan iş parçacığı sayısı.

from time import sleep

from rpython.rlib.rthread import start_new_thread, allocate_lock
from rpython.rlib.rarithmetic import r_int64, build_int, widen
from rpython.rlib.rbigint import rbigint

r_int8 = build_int('r_char', True, 8)

class ThreadEnv:
  __slots__ = ['n', 'counts', 'num_threads',
               'v_range', 'v_num', 'running', 'lock']

  def __init__(self):
    self.n = 0
    self.counts = [rbigint.fromint(0)]
    self.num_threads = 0
    self.v_range = [0]
    self.v_num = 0
    self.running = 0
    self.lock = None

env = ThreadEnv()

bt_bits = 12
bt_mask = (1<<bt_bits)-1
# computed compile time
bit_table = [r_int8(0)]
for i in xrange(1,1<<bt_bits):
  bit_table += [((i&1)<<1) + bit_table[i>>1]]

def main(argv):
  argc = len(argv)
  if argc < 2 or argc > 3:
    print 'Usage: %s N [NUM_THREADS=2]'%argv[0]
    return 1

  if argc == 3:
    env.num_threads = int(argv[2])
  else:
    env.num_threads = 2

  env.n = int(argv[1])
  env.counts = [rbigint.fromint(0)]*env.n
  env.lock = allocate_lock()

  v_range = []
  v_max = 1<<(env.n-1)
  v_num = 0
  v = (1<<(env.n>>1))-1
  while v < v_max:
    v_num += 1
    v_range += [v]
    if v&1:
      # special case odd v
      s = (v+1)&-v
      v ^= s|(s>>1)
    else:
      s = v&-v
      r = v+s
      # s is at least 2, skip two iterations
      i = 3
      s >>= 2
      while s:
        i += 1
        s >>= 1
      v = r|((v^r)>>i)
  env.v_range = v_range
  env.v_num = v_num

  for i in xrange(env.num_threads-1):
    start_new_thread(run,())

  # use the main process as a worker
  run()

  # wait for any laggers
  while env.running:
    sleep(0.05)

  result = []
  for i in range(env.n):
    result += [env.counts[i].lshift(env.n-i+3).str()]
  result += [env.counts[env.n-1].lshift(3).str()]
  print result
  return 0

def run():
  with env.lock:
    v_start = env.running
    env.running += 1

  n = env.n
  counts = [r_int64(0)]*n
  mask = (1<<n)-1
  v_range = env.v_range
  v_num = env.v_num
  z_count = 1<<(n-2)

  for i in xrange(v_start, v_num, env.num_threads):
    v = v_range[i]
    counts[0] += z_count
    counts[1] += v_num
    r = v^(v<<1)
    for w in v_range:
      # unroll counts[2] for speed
      # ideally, we could loop over x directly,
      # rather than over all v, only to throw the majority away
      # there's a 2x-3x speed improvement to be had here...
      x = w^r
      if widen(bit_table[x>>bt_bits]) + widen(bit_table[x&bt_mask]) == n:
        counts[2] += 1
        x, y = v, x
        o, k = 2, 3
        while k < n:
          # x = F ^ S
          # y = F ^ (S<<1)
          o = k
          z = (((x^y)<<1)^y)&mask
          # z is now F ^ (S<<2), possibly xor 1
          # what S and F actually are is of no consequence

          # the compiler hint `widen` let's the translator know
          # to store the result as a native int, rather than a signed char
          bt_high = widen(bit_table[z>>bt_bits])
          if bt_high + widen(bit_table[z&bt_mask]) == n:
            counts[k] += 1
            x, y = y, z
            k += 1
          elif bt_high + widen(bit_table[(z^1)&bt_mask]) == n:
            counts[k] += 1
            x, y = y, z^1
            k += 1
          else: k = n

  with env.lock:
    for i in xrange(n):
      env.counts[i] = env.counts[i].add(rbigint.fromrarith_int(counts[i]))
    env.running -= 1

def target(*args):
  return main, None

Derlemek için

Mercurial, git veya ne istersen kullanarak PyPy deposunun yerel bir klonunu yap . Aşağıdaki eklentiyi yazın (yukarıdaki betiğin isimlendirildiği varsayılarak convolution-high.py):

$ pypy %PYPY_REPO%/rpython/bin/rpython --thread convolution-high.py

Burada %PYPY_REPO%sadece klonladığınız depoya işaret eden bir ortam değişkenini temsil eder. Derleme yaklaşık bir dakika sürer.


Örnek Zamanlamaları

N = 16, 4 konu:

$ timeit convolution-high-c 16 4
[55276229099520, 10855179878400, 2137070108672, 420578918400, 83074121728, 16540581888, 3394347008, 739659776, 183838720, 57447424, 23398912, 10749184, 5223040, 2584896, 1291424, 645200, 322600]
Elapsed Time:     0:00:00.109
Process Time:     0:00:00.390

N = 18, 4 konu:

$ timeit convolution-high-c 18 4
[3341140958904320, 619683355033600, 115151552380928, 21392898654208, 3982886961152, 744128512000, 141108051968, 27588886528, 5800263680, 1408761856, 438001664, 174358528, 78848000, 38050816, 18762752, 9346816, 4666496, 2333248, 1166624]
Elapsed Time:     0:00:01.250
Process Time:     0:00:04.937

N = 20, 4 iplik:

$ timeit convolution-high-c 20 4
[203141370301382656, 35792910586740736, 6316057966936064, 1114358247587840, 196906665902080, 34848574013440, 6211866460160, 1125329141760, 213330821120, 44175523840, 11014471680, 3520839680, 1431592960, 655872000, 317675520, 156820480, 78077440, 39005440, 19501440, 9750080, 4875040]
Elapsed Time:     0:00:15.531
Process Time:     0:01:01.328

N = 22, 4 iplik:

$ timeit convolution-high-c 22 4
[12410090985684467712, 2087229562810269696, 351473149499408384, 59178309967151104, 9975110458933248, 1682628717576192, 284866824372224, 48558946385920, 8416739196928, 1518499004416, 301448822784, 71620493312, 22100246528, 8676573184, 3897278464, 1860960256, 911646720, 451520512, 224785920, 112198656, 56062720, 28031360, 14015680]
Elapsed Time:     0:03:23.156
Process Time:     0:13:25.437

09:26. 22 mürettebata hoş geldin :)

Nedenini bilmiyorum ama yeni sürümün benim için daha hızlı değil. Hala zaman zaman 9:30 gibi. / Erken 22 8.

@ Bölüşümün ortalama 3 sağ vardiya kadar hızlı olması durumunda mantıklı olacak olan Lembik (3 = Toplam {(n + 1) / (2 ^ n)}, n = 1..infty). Certian mimarileri için, durumun bu olabileceğini düşünüyorum, ancak benimkinde mayın bölünmesi oldukça yavaş. Test etmek için zaman ayırdığınızdan dolayı teşekkür ederiz :)
primo

3

Python 3.3, N = 20, 3,5 dak

Yasal Uyarı: niyetindeyim DEĞİL kullanıyorum algoritma sadece utanmaz liman olduğu için, benim kendi cevap olarak bu post Primo RPython çözümü . Amacım, sadece Numpy'nin büyüsünü birleştirirseniz Python'da neler yapabileceğinizi göstermek. ve Numba modüllerinin .

Numba kısaca açıkladı:

Numba, açıklamalı özel bir derleyicidir ve açıklamalı Python ve NumPy kodunu LLVM'ye (dekoratörler aracılığıyla) derler. http://numba.pydata.org/

Güncelleme 1 : Sayıları çevreledikten sonra bazı sayıları tamamen atlayabileceğimizi fark ettim. Yani şimdi maxf olur (1 << n) // 2 ve maxs olur maxf ** 2. Bu işlem süreci biraz hızlandıracak. n = 16 şimdi yalnızca ~ 48 saniye alır (4,5 dakikadan aşağıya). Ayrıca biraz daha hızlı ilerletip geliştiremeyeceğimi görmeye çalışacağım başka bir fikrim var.

Güncelleme 2: Değişen algoritma (primo çözümü). Bağlantı noktam henüz okuyucuyu desteklemese de eklemek oldukça önemsiz. Numba ve ctypes kullanarak CPython GIL'i serbest bırakmak bile mümkündür. Ancak bu çözüm, tek çekirdekte de çok hızlı çalışıyor!

import numpy as np
import numba as nb

bt_bits = 11
bt_mask = (1 << bt_bits) - 1
bit_table = np.zeros(1 << bt_bits, np.int32)

for i in range(0, 1 << bt_bits):
    bit_table[i] = ((i & 1) << 1) + bit_table[i >> 1]

@nb.njit("void(int32, int32, int32, int32, int64[:], int64[:])")
def run(n, m, start, re, counts, result):
    mask = (1 << n) - 1

    v_max = (1 << n) // 2
    rr = v_max // 2

    v = (1 << (n >> 1)) - 1
    while v < v_max:
        s = start

        while s < rr:
            f = v ^ s
            counts[0] += 8
            t = s << 1
            o, j = 0, 1

            while o < j and j < m:
                o = j
                w = (t ^ f) & mask
                bt_high = bit_table[w >> bt_bits]

                if bt_high + bit_table[w & bt_mask] == n:
                    counts[j] += 8
                    t <<= 1
                    j += 1
                elif bt_high + bit_table[(w ^ 1) & bt_mask] == n:
                    counts[j] += 8
                    t = (t | 1) << 1
                    j += 1
                    s += re

            s = v & -v
            r = v + s
            o = v ^ r
            o = (o >> 2) // s
            v = r | o

    for e in range(m):
        result[e] += counts[e] << (n - e)

Ve sonunda:

if __name__ == "__main__":
    n = 20
    m = n + 1

    result = np.zeros(m, np.int64)
    counts = np.zeros(m, np.int64)

    s1 = time.time() * 1000
    run(n, m, 0, 1, counts, result)
    s2 = time.time() * 1000

    print(result)
    print("{0}ms".format(s2 - s1))

Bu, makinemde 212688ms veya ~ 3.5 dak.


Teşekkürler. Şimdi n = 18? :)

Programa n = 18 kullanarak başladığımdan bu yana neredeyse 20 dakika geçti, Python'un bu belirli algoritmayı kullanarak Numba ile bile zamanında çözemediğini söylemenin güvenli olduğunu düşünüyorum.
Anna Jokela

Daha iyi bir algoritma mevcut olduğuna iyimserim.

Pip install numba'yı denedim ama llvmpy'yi bulamadığını söylüyor. Sudo pip install llvmpy'yi denedim, ancak versioneer bulamadığını söylüyor. Sudo pip install versioneer'ı denedim ama zaten sahip olduğumu söylüyor.

Henüz çalışmak için numba olmamasına rağmen (sonunda anakonda yüklemek zorunda kalacağımı düşünüyorum) bundan etkilendim. Asıl soru, N = 22'yi nimrod'a benzer bir yöntem kullanarak çözebiliyor musunuz?

2

C ++ N = 16

Bir atom ile bir EEEPC üzerinde test ediyorum .. benim zamanım pek mantıklı gelmiyor. : D
Atom 34 saniye içinde n = 14 çözer. Ve 20 dakika içinde n = 16. OP PC'de n = 16'yı test etmek istiyorum. Ben iyimserim.

Fikirler, belirli bir F için her zaman bir çözüm bulduğumuzda 2 ^ i çözümünü bulduk çünkü S'nin alt kısmını aynı sonuca götürecek olanı değiştirebiliriz.

#include <stdio.h>
#include <cinttypes>
#include <cstring>

int main()
{
   const int n = 16;
   const int m = n + 1;
   const uint64_t maxS = 1ULL << (2*n);
   const uint64_t maxF = 1ULL << n;
   const uint64_t mask = (1ULL << n)-1;
   uint64_t out[m]={0};
   uint64_t temp[m] = {0};
   for( uint64_t F = 0; F < maxF; ++F )
   {
      for( uint64_t S = 0; S < maxS; ++S )
      {
         int numSolution = 1;
         for( int i = n; i >= 0; --i )
         {
            const uint64_t window = S >> i;
            if( __builtin_popcount( mask & (window ^ F) ) == (n / 2) )
            {
               temp[i] += 1;
            } else {
               numSolution = 1 << i;
               S += numSolution - 1;
               break;
            }
         }
         for( int i = n; i >= 0; --i )
         {
            out[i] += temp[i]*numSolution;
            temp[i] = 0;
         }
      }
   }
   for( int i = n; i >= 0; --i )
   {
      uint64_t x = out[i];
      printf( "%lu ", x );
   }
   return 0;
}

derlemek için:

gcc 26459.cpp -std = c ++ 11 -O3-march = yerel -fstrict-aliasing -ftree-vectorize -Wall -pedantic -o 26459


1
Bu harika. Aslında daha büyük n için nasıl çözüleceği hakkında bazı yarı pişmiş fikirler var. Onları duymak ister misiniz, yoksa rekabeti mahvedebilir mi?

2

JAVASCRIPT n: 12

Bilgisayarımda 231.242 saniye sürdü. Demo'da tarayıcının donmasını önlemek için web işçileri kullanıyorum. Bu kesin paralel çalışanlarla daha da geliştirilebilir. JS'nin bu zorlukta bir şansı olmadığını biliyorum ama eğlenmek için yaptım!

Online Demosu çalıştırmak için tıklayın

var n = 8;        
var m = n + 1;
var o = [];
var popCount = function(bits) {
  var SK5  = 0x55555555,
      SK3  = 0x33333333,
      SKF0 = 0x0f0f0f0f,
      SKFF = 0xff00ff;

  bits -= (bits >> 1) & SK5;
  bits  = (bits & SK3) + ((bits >> 2) & SK3);
  bits  = (bits & SKF0) + ((bits >> 4) & SKF0);
  bits += bits >> 8;

  return (bits + (bits >> 15)) & 63;
};
for(var S = 0; S < (1 << n + m - 1); S += 2){
  for(var F = 0; F < (1 << n - 1); F += 1){
    for (var i = 0; i < m; i++){
      var c = popCount(((S >> i) & ((1 << n) - 1)) ^ F);
      if(c == n >> 1){
        if(!o[i]) o[i] = 0;
        o[i] += 4;
      } else break;
    }
  }
}
return o;

Peki ya yeni (hızlı) hızlı javascript motorlarından biri? Bunlar kullanılabilir mi?

Dart gibi bir şey mi demek istiyorsun ?
rafaelcastrocouto 08

1
Aslında yanılıyorum. Hem firefox hem de kromu deneyebilirsiniz. Tabii asm.js yazmak istemiyorsanız :)

1
itiraz kabul edildi ... yapacak!
rafaelcastrocouto

1
Bunu denedim ve bilgisayarımı 5.4 saniye sürdü n=22 [235388928,86292480,19031048,5020640,1657928,783920,545408,481256,463832,460256,459744,459744,459744,459744,459744,459744,459744,459744,459744,459744,459744,459744] i.imgur.com/FIJa2Ch.png
Spedwards

1

Fortran: n = 12

Fortran’da Quick'n'dirty versiyonunu yeni yaptım, OpenMP dışında optimizasyon yok. OPs makinesinde n = 12 için 10 dakikadan biraz daha kısa sürede sıkılmalıdır, makinemde yavaşça yavaşlayan 10:39 alır.

64-bit tamsayıların gerçekten olumsuz bir etkisi var; Sanırım bunun için daha hızlı olması için tüm algoritmayı tekrar düşünmek zorunda kalacağım. Rahatsız edip edemeyeceğimi bilmiyorum, sanırım kendi zevkime göre daha iyi bir meydan okuma düşünerek biraz zaman geçirmeyi tercih ederim. Başkası bunu almak ve onunla koşmak isterse devam et :)

program golf
use iso_fortran_env
implicit none
integer, parameter ::  n=12
integer :: F(n), S(2*n)
integer(int64) :: leadingzerocounts(n+1)
integer :: k
integer(int64) :: i,j,bindec,enc

leadingzerocounts=0

!$OMP parallel do private(i,enc,j,bindec,S,F,k) reduction(+:leadingzerocounts) schedule(dynamic)
do i=0,2**(2*n)-1
  enc=i
  ! Short loop to convert i into the array S with -1s and 1s
  do j=2*n,1,-1
    bindec=2**(j-1)
    if (enc-bindec .ge. 0) then
      S(j)=1
      enc=enc-bindec
    else
      S(j)=-1
    endif
  end do
  do j=0,2**(n)-1
    ! Convert j into the array F with -1s and 1s
    enc=j
    do k=n,1,-1
      bindec=2**(k-1)
      if (enc-bindec .ge. 0) then
        F(k)=1
        enc=enc-bindec
      else
        F(k)=-1
      endif
    end do
    ! Compute dot product   
    do k=1,n+1
      if (dot_product(F,S(k:k+n-1)) /= 0) exit
      leadingzerocounts(k)=leadingzerocounts(k)+1
    end do
  end do
end do
!$OMP end parallel do

print *, leadingzerocounts

end

1

Lua: n = 16

Feragatname: Niyetim bunu kendi cevabım olarak yayınlamamak değil, kullandığım algoritma Anna Jokela'nın akıllı cevabından utanmadan çalındığı için . ilmale'nin akıllı cevabından utanmadan çalındı .

Ayrıca, geçerli bile değil - kayan nokta sayısından kaynaklanan yanlışlıklar var (Lua'nın 64-bit tam sayıları desteklemesi daha iyi olur). Ancak, ben hala yüklüyorum, sadece bu çözümün ne kadar hızlı olduğunu göstermek için. Dinamik bir programlama dilidir ve yine de n = 16'yı makul bir sürede (800MHz CPU'da 1 dakika) hesaplayabilirim.

LuaJIT ile çalıştırın, standart tercüman çok yavaş.

local bit = require "bit"
local band = bit.band
local bor = bit.bor
local bxor = bit.bxor
local lshift = bit.lshift
local rshift = bit.rshift

-- http://stackoverflow.com/a/11283689/736054
local function pop_count(w)
    local b1 = 1431655765
    local b2 = 858993459
    local b3 = 252645135
    local b7 = 63

    w = band(rshift(w, 1), b1) + band(w, b1)
    w = band(rshift(w, 2), b2) + band(w, b2)
    w = band(w + rshift(w, 4), b3)
    return band(rshift(w, 24) + rshift(w, 16) + rshift(w, 8) + w, b7)
end

local function gen_array(n, value)
    value = value or 0
    array = {}
    for i = 1, n do
        array[i] = value
    end
    return array
end

local n = 16
local u = math.floor(n / 2)
local m = n + 1
local maxf = math.floor(lshift(1, n) / 2)
local maxs = maxf ^ 2
local mask = lshift(1, n) - 1

local out = gen_array(m, 0)
local temp = gen_array(m, 0)


for f = 0, maxf do
    local s = 0
    while s <= maxs do
        local num_solution = 1

        for i = n, 0, -1 do
            if pop_count(band(mask, bxor(rshift(s, i), f))) == u then
                temp[i + 1] = temp[i + 1] + 8
            else
                num_solution = lshift(1, i)
                s = s + num_solution - 1
                break
            end
        end

        for i = 1, m do
            out[i] = out[i] + temp[i] * num_solution
            temp[i] = 0
        end

        s = s + 1
    end
end

for i = m, 1, -1 do
    print(out[i])
end

Teşekkür ederim. Sanırım son Lua sürümleri 64 bitlik bir sistemde 64 bit olması gereken uzun ve uzun int kullanıyor. Lua.org/work/doc/manual.html adresindeki "lua_integer" başlığına bakın .

@Lembik: İlginç. Her iki durumda da (zaten destekler 's standart Lua long longyerine doublebir derleme ayarıyla) değil, LuaJIT.
Konrad Borowski

Sanırım Lurtit ile her durumda yanılmışım. Biri olmayan 5.3'e ihtiyaç duyardı. Lua'nın verebileceği en iyi tavsiye "5.3-workx'i dene" idi.
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.