Ver Fonte

* LSFR Random

Ranides Atterwim há 13 anos atrás
pai
commit
c47081321c

+ 12 - 0
pom.xml

@@ -28,6 +28,18 @@
                     <compilerArgument>-proc:none</compilerArgument>
                 </configuration>
             </plugin>
+            <!-- Pamięć dla LFSRTest -->
+<!--            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>2.13</version>
+                <configuration>
+                    <forkMode>pertest</forkMode>
+                    <argLine>-Xms768m -Xmx768m</argLine>
+                    <testFailureIgnore>false</testFailureIgnore>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>-->
         </plugins>
     </build>
     

+ 70 - 0
src/main/java/net/ranides/assira/math/LFSR.java

@@ -0,0 +1,70 @@
+/*
+ * I-BS.pl PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ * Copyright (c) 2012, I-BS.pl and/or its affiliates. All rights reserved.
+ */
+package net.ranides.assira.math;
+
+import java.util.Random;
+
+/**
+ * Generator liczb pseudolosowych o bardzo długiej serii bez cyklu.
+ * Formalnie nie jest przeliczona długość cyklu. Empirycznie dla kilku seed'ów 
+ * zostało sprawdzonych pierwsze 64 mln elementów:
+ * 17, 32, 40, 197
+ * @author ranides
+ */
+public final class LFSR extends Random {
+
+    private static final int M = 32;
+    // hard-coded for 32-bits
+    private static final int[] TAPS = {1, 2, 22, 32};
+    
+    private boolean[] vector;
+
+    public LFSR() {
+        this( (int)System.nanoTime() );
+    }
+    
+    public LFSR(int seed) {
+        super(seed);
+    }
+    
+    @Override
+    synchronized public void setSeed(long seed) {
+        vector = new boolean[M + 1];
+        for (int i = 0; i < M; i++) {
+            vector[i] = (seed & (1 << i)) != 0;
+        }
+        super.setSeed(0);
+    }
+
+    @Override
+    public synchronized int next(int bits) {
+        // nawet jeśli dla liczby używamy tylko [bits] rejestrów
+        // to w następnych krokach wykonujemy standardowe przesunięcie całej sekwencji
+        int result = 0;
+        for (int i = 0; i < bits; i++) {
+            result |= (vector[i] ? 1 : 0) << i;
+        }
+
+        // zero jest dopuszczalne. tracimy co prawda wartość -2^31
+        if (result < 0) {
+            result++;
+        }
+
+        // modyfikacja ostatniego rejestru na podstawie wyróżnionych rejestrów
+        vector[M] = false;
+        for (int i = 0; i < TAPS.length; i++) {
+            vector[M] ^= vector[M - TAPS[i]];
+        }
+
+        // przesunięcie całego wektora
+        for (int i = 0; i < M; i++) {
+            vector[i] = vector[i + 1];
+        }
+
+        return result;
+    }
+
+}
+

+ 115 - 0
src/test/java/net/ranides/assira/math/LFSRTest.java

@@ -0,0 +1,115 @@
+/*
+ * I-BS.pl PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ * Copyright (c) 2012, I-BS.pl and/or its affiliates. All rights reserved.
+ */
+package net.ranides.assira.math;
+
+import java.util.Arrays;
+import java.util.Random;
+import static org.junit.Assert.*;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ * Uwaga - test musi mieć dostępne 512 MB pamięci. Patrz: "pom.xml"
+ * @author ranides
+ */
+@SuppressWarnings("PMD.SystemPrintln")
+public class LFSRTest {
+    
+    private static final int MAX_CYCLE = 64 * 1000 * 1000;
+    
+    private BS buffer;
+    
+    public LFSRTest() {
+    }
+    
+    private BS resetBuffer() {
+        if( buffer == null) {
+            buffer = new BS();
+        }
+        return buffer;
+    }
+
+    private int testCycle(Random generator, int seed) {
+        // Intel Core i3 540 @ 3.07GHz
+        // Czas przeszukiwania 320 mln / 164 s
+        // 
+        // czyli 1 seed na około 40 minut
+        resetBuffer();
+        
+        buffer.clear(true);
+        for (int i = 0; i<MAX_CYCLE; i++) {
+            if( buffer.exists( generator.nextInt() ) ) {
+                System.out.printf("cycle length for seed %d = %d.\n", seed, i);
+                return i;
+            }
+        }
+        
+        buffer.clear(false);
+        for (int i = 0; i<MAX_CYCLE; i++) {
+            if( buffer.exists( generator.nextInt() ) ) {
+                System.out.printf("cycle length for seed %d = %d.\n", seed, i);
+                return i;
+            }
+        }
+        
+        System.out.printf("cycle length for seed %d > %d.\n", seed, MAX_CYCLE);
+        return MAX_CYCLE;
+    }
+    
+    
+    @Ignore("manual slow")
+    @Test
+    public void testCycles() {
+        
+        assertEquals( 115135, testCycle(new Random(0), 0) );
+        assertEquals( 94482, testCycle(new Random(17), 17) );
+        assertEquals( 78192, testCycle(new Random(32), 32) );
+        assertEquals( 192385, testCycle(new Random(40), 40) );
+        assertEquals( 66466, testCycle(new Random(170), 170) );
+        assertEquals( 112008, testCycle(new Random(197), 197) );
+        
+        assertEquals( 1, testCycle(new LFSR(0), 0) );
+        assertEquals( MAX_CYCLE, testCycle(new LFSR(17), 17) );
+        assertEquals( MAX_CYCLE, testCycle(new LFSR(32), 32) );
+        assertEquals( MAX_CYCLE, testCycle(new LFSR(40), 40) );
+        assertEquals( MAX_CYCLE, testCycle(new LFSR(170), 170) );
+        assertEquals( MAX_CYCLE, testCycle(new LFSR(197), 197) );
+    }
+    
+    private static class BS {
+        
+        private char words[] = new char[128 * 1024 * 1024];
+        private boolean pmode;
+        
+        public boolean exists(int value) {
+            return pmode ? existsP(value) : existsN(value);
+        }
+        
+        private boolean existsP(int value) {
+            if(value < 0) {
+                return false;
+            } else {
+                int offset = value / 16;
+                int mask = 1 << (value % 16);
+                boolean exists = (mask == (words[offset] & mask));
+                words[offset] |= mask;
+                return exists;
+            }
+        }
+        
+        private boolean existsN(int value) {
+            if(value > 0) {
+                return false;
+            } else {
+                return existsP(-value);
+            }
+        }
+        
+        void clear(boolean pmode) {
+            Arrays.fill(words, 0, words.length, '\0');
+            this.pmode = pmode;
+        }
+    }
+}