Sobol sequence 2D/3D

Mostly working Sobol sequences in two and three dimensions. The non-working part is that they don’t wrap properly…so you can “only” create 232 values.


public final class Sobol2D
{
  // state data
  private int i,d0,d1;

  // direction table
  private static final int[] D;
  
  static {
    D = new int[33];
    
    int c = D[0] = 1 << 31;
    
     for(int i=1; i<32; i++) {
       c = c ^ (c >>> 1);
       D[i] = c;
     }
     
     // TODO: what about -1? index 32
  }
  
  private final void updateState()
  {
    int c = Integer.numberOfTrailingZeros(~i);
    d1 ^= D[c];
    d0 ^= 0x80000000 >>> c;
    i  += 1;    
  }
  
  /** Return current index into the stream. */
  public final int getPos() { return i; }
  
  /** */
  public final void seek(int num)
  {
    int n = i + num;
    int a = i ^ (i >>> 1);
    int b = n ^ (n >>> 1);
    int d = a ^ b;
    
    int c = 0;
    
    while(d != 0) {
      if ((d & 1) != 0) {
        d0 ^= 0x80000000 >>> c;
        d1 ^= D[c];
      }
      d >>>= 1;
      c   += 1;
    }
    
    i = n;    
  }
  
  
  public Sobol2D() { seed(0,0); }
  
  public Sobol2D(int seedX, int seedY)
  {
    seed(seedX, seedY);
  }
  
  public final void seed(int s0, int s1)
  {
    d0 = s0;
    d1 = s1;
    i  = 0;
  }
  
  public final void next(float[] v, int off)
  {
    v[off++] = (d0 >>> 8) * 0x1p-24f;
    v[off++] = (d1 >>> 8) * 0x1p-24f;
    updateState();
  }
  
  public final void next(float[] v) { next(v, 0); }
  
  public final void next(java.nio.FloatBuffer fb)
  {
    fb.put((d0 >>> 8) * 0x1p-24f);
    fb.put((d1 >>> 8) * 0x1p-24f);
    updateState();
  }
}

public final class Sobol3D
{
  // state data for the sequence
  private int i,d0,d1,d2;

  // direction table
  private static final int[] D;
  
  // build the direction tables
  static {
    // TODO: 'i' = -1 is not handled
    
    D = new int[65];

    // second dimension
    int c = 1 << 31;
    
    D[0] = c;
    
     for(int i=2; i<64; i+=2) {
       c = c ^ (c >>> 1);
       D[i] = c;
     }
     
     // third dimension
     int s0,s1,t;
     
     s0 = D[1] = D[0];
     s1 = D[3] = D[2];
     
     for (int i=4; i<64; i+=2) {
       t   = s1;
       s1 ^= s0 ^ (s0 >>> 2);
       s0  = t;
       
       D[i+1] = s1;
     }
  }
  
  /** */
  public Sobol3D() { d0=d1=d2=i=0; }
  
  /** */
  public final void seed(int s0, int s1, int s2)
  {
    d0 = s0;
    d1 = s1;
    d2 = s2;
    i  = 0;
  }

  /** Return current index into the stream. */
  public final int getPos() { return i; }
  
  /** */
  private final void updateState()
  {
    int c = Integer.numberOfTrailingZeros(~i);
    int o = c+c;
    
    d0 ^= 0x80000000 >>> c;
    d1 ^= D[o];
    d2 ^= D[o+1];
    i  += 1;
  }
  
  /** */
  public final void seek(int num)
  {
    int n = i + num;
    int a = i ^ (i >>> 1);
    int b = n ^ (n >>> 1);
    int d = a ^ b;
    
    int c = 0;
    
    while(d != 0) {
      if ((d & 1) != 0) {
        d0 ^= 0x80000000 >>> c;
        d1 ^= D[c+c];
        d2 ^= D[c+c+1];
      }
      
      d >>>= 1;
      c   += 1;
    }
    
    i = n;    
  }

  
  /** */
  public final void next(float[] v, int off)
  {
    v[off++] = (d0 >>> 8) * 0x1p-24f;
    v[off++] = (d1 >>> 8) * 0x1p-24f;
    v[off++] = (d2 >>> 8) * 0x1p-24f;
    
    updateState();
  }
  
  /** */
  public final void next(float[] v) { next(v,0); }
  
  public final void next(java.nio.FloatBuffer fb)
  {
    fb.put((d0 >>> 8) * 0x1p-24f);
    fb.put((d1 >>> 8) * 0x1p-24f);
    fb.put((d2 >>> 8) * 0x1p-24f);
    updateState();
  }
}

Updated version now live here: https://github.com/roquendm/JGO-Grabbag/tree/master/src/roquen/math/lds