All Downloads are FREE. Search and download functionalities are using the official Maven repository.

umontreal.iro.lecuyer.util.BitVector Maven / Gradle / Ivy

Go to download

SSJ is a Java library for stochastic simulation, developed under the direction of Pierre L'Ecuyer, in the Département d'Informatique et de Recherche Opérationnelle (DIRO), at the Université de Montréal. It provides facilities for generating uniform and nonuniform random variates, computing different measures related to probability distributions, performing goodness-of-fit tests, applying quasi-Monte Carlo methods, collecting (elementary) statistics, and programming discrete-event simulations with both events and processes.

The newest version!

/*
 * Class:        BitVector
 * Description:  implements vectors of bits and their operations
 * Environment:  Java
 * Software:     SSJ 
 * Copyright (C) 2001  Pierre L'Ecuyer and Université de Montréal
 * Organization: DIRO, Université de Montréal
 * @author       
 * @since

 * SSJ is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License (GPL) as published by the
 * Free Software Foundation, either version 3 of the License, or
 * any later version.

 * SSJ is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * A copy of the GNU General Public License is available at
   GPL licence site.
 */

package umontreal.iro.lecuyer.util; 

import java.io.Serializable;



/**
 * This class implements vectors of bits and the operations needed to use
 * them. The vectors can be of arbitrary length. The operations provided are
 * all the binary operations available to the int and long
 * primitive types in Java.
 * 
 * 

* All bit operations are present in two forms: a normal form and a self * form. The normal form returns a newly created object containing the result, * while the self form puts the result in the calling object (this). * The return value of the self form is the calling object itself. This is * done to allow easier manipulation of the results, making it possible to * chain operations. * */ public class BitVector implements Serializable, Cloneable { static final long serialVersionUID = -3448233092524725148L; private int[] v; //the bits data private int length; //number of data bits (in bits, not in bytes) private final static int all_1 = -1; //integer with all bits set to 1 private final static int one_1 = 1; //integer with only his last bit set to 1 /* Note sur le format interne du vecteur de bits : On fait toujours en sorte que les bits redondants (ceux qui apparaissent quand length % 32 != 0) soient mis a 0. Ceci permet de faire des operations entre des vecteurs de longeurs differentes en posant que les bits manquants sur le plus petit des deux vecteurs ont la valeur 0. */ /** * Creates a new BitVector of length length with * all its bits set to 0. * * @param length the length of the BitVector * * */ public BitVector (int length) { this.length = length; v = new int[(length + 31) / 32]; for(int i = 0; i < v.length; i++) v[i] = 0; } /** * Creates a new BitVector of length length using * the data in vect. Component vect[0] makes the 32 lowest order * bits, * with vect[1] being the 32 next lowest order bits, and so on. * The normal bit order is then used to fill the 32 bits (the first bit * is the lowest order bit and the last bit is largest order bit). * Note that the sign bit is used as the largest order bit. * * @param vect the bits data * * @param length the length of the vector * * @exception IllegalArgumentException when the length of vect is * not compatible with the length provided * * */ public BitVector (int[] vect, int length) { if (((length + 31)/ 32) != vect.length) throw new IllegalArgumentException ("The int[] length must be equal to the (length + 31) / 32"); this.length = length; v = new int[vect.length]; for(int i = 0; i < vect.length; i++) v[i] = vect[i]; //the extra bits must be set at zero v[v.length - 1] &= (all_1 >>> (31 - (length - 1) % 32)); } /** * Creates a new BitVector using the data in vect. * The length of the BitVector is always equals to 32 times the * length of vect. * * @param vect the bits data * * */ public BitVector (int[] vect) { this(vect, vect.length * 32); } /** * Creates a copy of the BitVector that. * * @param that the BitVector to copy * */ public BitVector (BitVector that) { this.length = that.length; this.v = new int[that.v.length]; for(int i = 0; i < that.v.length; i++) this.v[i] = that.v[i]; } /** * Creates a copy of the BitVector. * * @return a deep copy of the BitVector * */ public Object clone() { try{ BitVector c = (BitVector)super.clone(); c.v = (int[])v.clone(); return c; }catch(CloneNotSupportedException e) { IllegalStateException ne = new IllegalStateException(); ne.initCause(e); throw ne; } } /** * Verifies if two BitVector's have the same length and * the same data. * * @param that the other BitVector to compare to * * @return if the two BitVector's are identiqual * */ public boolean equals (BitVector that) { if(this.length != that.length) return false; for(int i = 0; i < this.v.length; i++) if(this.v[i] != that.v[i]) return false; return true; } /** * Returns the length of the BitVector. * * @return the length of the BitVector * */ public int size() { return length; } /** * Resizes the BitVector so that its length is equal * to size. If the BitVector is enlarged, then the newly * added bits are given the value 1 if filling is set to * true and 0 otherwise. * * @param size the new size of the BitVector * * @param filling the state of the new bits * * */ public void enlarge (int size, boolean filling) { if(size < 0) throw new NegativeArraySizeException ("The BitVector must have a non-negative size"); if(filling && (length % 32) != 0) v[v.length - 1] ^= all_1 << (length % 32); if((size + 31) / 32 != v.length) { int[] new_v = new int[(size + 31) / 32]; int i; for(i = 0; i < new_v.length && i < v.length; i++) new_v[i] = v[i]; for(; i < new_v.length; i++) new_v[i] = filling ? all_1 : 0; v = new_v; } length = size; //the extra bits must be set at zero v[v.length - 1] &= (all_1 >>> (31 - (length - 1) % 32)); } /** * Resizes the BitVector so that its length is equal * to size. Any new bit added is set to 0. * * @param size the new size of the BitVector * * */ public void enlarge (int size) { enlarge(size, false); } /** * Gives the value of the bit in position pos. If the * value is 1, returns true; otherwise, returns false. * * @param pos the position of the checked bit * * @return the value of the bit as a boolean * @exception ArrayIndexOutOfBoundsException if pos is outside * the range of the BitVector * * */ public boolean getBool (int pos) { if(pos < 0 || pos >= length) throw new ArrayIndexOutOfBoundsException(pos); return (v[pos >>> 5] & (one_1 << (pos & 31))) != 0; } /** * Sets the value of the bit in position pos. If value * is equal to true, sets it to 1; otherwise, sets it to 0. * * @param pos the position of the bit to modify * * @param value the new value of the bit as a boolean * * @exception ArrayIndexOutOfBoundsException if pos is outside * the range of the BitVector * * */ public void setBool (int pos, boolean value) { if(pos > length || pos < 0) throw new ArrayIndexOutOfBoundsException(pos); if(value) v[pos / 32] |= (one_1 << (pos % 32)); else v[pos / 32] &= (one_1 << (pos % 32)) ^ all_1; } /** * Returns an int containing all the bits in the interval * * [pos×32,pos×32 + 31]. * * @param pos the selected position * * @return the int at the specified position * @exception ArrayIndexOutOfBoundsException if pos is outside * the range of the BitVector * * */ public int getInt (int pos) { if(pos >= v.length || pos < 0) throw new ArrayIndexOutOfBoundsException(pos); return v[pos]; } /** * Returns a string containing all the bits of the BitVector, * starting with the highest order bit and finishing with the lowest order bit. * The bits are grouped by groups of 8 bits for ease of reading. * * @return all the bits of the BitVector * */ public String toString() { StringBuffer sb = new StringBuffer(); for(int i = length - 1; i > 0; i--) sb.append(getBool(i) ? "1" : "0").append(i%8 == 0 ? " " : ""); sb.append(getBool(0) ? "1" : "0"); return sb.toString(); } /** * Returns a BitVector which is the result of the not * operator on the current BitVector. The not operator is * equivalent to the ~ operator in Java and thus swap all bits (bits * previously set to 0 become 1 and bits previously set to 1 become 0). * * @return the effect of the not operator * */ public BitVector not() { BitVector bv = new BitVector(length); for(int i = 0; i < v.length; i++) bv.v[i] = v[i] ^ all_1; //the extra bits must be set at zero bv.v[v.length - 1] &= (all_1 >>> (31 - (length - 1) % 32)); return bv; } /** * Applies the not operator on the current BitVector * and returns it. * * @return the BitVector itself * */ public BitVector selfNot() { for(int i = 0; i < v.length; i++) v[i] = v[i] ^ all_1; //the extra bits must be set at zero v[v.length - 1] &= (all_1 >>> (31 - (length - 1) % 32)); return this; } /** * Returns a BitVector which is the result of the xor * operator applied on this and that. The xor operator is * equivalent to the ^ operator in Java. All bits which were set to 0 in * one of the vector and to 1 in the other vector are set to 1. The others * are set to 0. This is equivalent to the addition in modulo 2 arithmetic. * * @param that the second operand to the xor operator * * @return the result of the xor operation * */ public BitVector xor (BitVector that) { //we always consider that this is longer than that if(that.length > this.length) return that.xor(this); BitVector bv = new BitVector(this.length); int max = this.v.length; int min = that.v.length; for(int i = 0; i < min; i++) bv.v[i] = this.v[i] ^ that.v[i]; for(int i = min; i < max; i++) bv.v[i] = this.v[i]; return bv; } /** * Applies the xor operator on this with that. * Stores the result in this and returns it. * * @param that the second operand to the xor operator * * @return this * */ public BitVector selfXor (BitVector that) { //we assume that this is large enough to contain that if(this.length < that.length) this.enlarge(that.length); int min = that.v.length; for(int i = 0; i < min; i++) this.v[i] ^= that.v[i]; return this; } /** * Returns a BitVector which is the result of the and * operator with both the this and that BitVector's. The * and operator is equivalent to the & operator in Java. Only * bits which are set to 1 in both this and that are set to 1 * in the result, all the others are set to 0. * * @param that the second operand to the and operator * * @return the result of the and operation * */ public BitVector and (BitVector that) { //we always consider this as longer than that if(that.length > this.length) return that.and(this); BitVector bv = new BitVector(this.length); int max = this.v.length; int min = that.v.length; for(int i = 0; i < min; i++) bv.v[i] = this.v[i] & that.v[i]; if(that.length % 32 != 0) bv.v[min - 1] |= this.v[min - 1] & (all_1 << (that.length % 32)); for(int i = min; i < max; i++) bv.v[i] = 0; return bv; } /** * Applies the and operator on this with that. * Stores the result in this and returns it. * * @param that the second operand to the and operator * * @return this * */ public BitVector selfAnd (BitVector that) { //we assume that this is large enough to contain that if(this.length < that.length) this.enlarge(that.length, true); int min = that.v.length; for(int i = 0; i < min - 1; i++) this.v[i] &= that.v[i]; this.v[min - 1] &= (that.v[min - 1] | (all_1 << (that.length % 32))); return this; } /** * Returns a BitVector which is the result of the or * operator with both the this and that BitVector's. The * or operator is equivalent to the | operator in Java. Only * bits which are set to 0 in both this and that are set to to 0 * in the result, all the others are set to 1. * * @param that the second operand to the or operator * * @return the result of the or operation * */ public BitVector or (BitVector that) { //we always consider this is longer than that if(that.length > this.length) return that.or(this); BitVector bv = new BitVector(this.length); int max = this.v.length; int min = that.v.length; for(int i = 0; i < min; i++) bv.v[i] = this.v[i] | that.v[i]; for(int i = min; i < max; i++) bv.v[i] = 0; return bv; } /** * Applies the or operator on this with that. * Stores the result in this and returns it. * * @param that the second operand to the or operator * * @return this * */ public BitVector selfOr (BitVector that) { //we assume that this is large enough to contain that if(this.length < that.length) this.enlarge(that.length); int min = that.v.length; for(int i = 0; i < min; i++) this.v[i] |= that.v[i]; return this; } /** * Returns a BitVector equal to the original with * all the bits shifted j positions to the right if j is * positive, and shifted j positions to the left if j is negative. * The new bits that appears to the left or to the right are set to 0. * If j is positive, this operation is equivalent to the »> * operator in Java, otherwise, it is equivalent to the « operator. * * @param j the size of the shift * * @return the shifted BitVector * */ public BitVector shift (int j) { BitVector bv = new BitVector(length); if(j == 0) return bv; else if(j > 0) { int a = j / 32; int b = j % 32; int c = 32 - b; int i; for(i = 0; i+a < v.length; i++) bv.v[i] = v[i+a] >>> b; // la retenue for(i = 0; i+a+1 < v.length; i++) bv.v[i] ^= v[i+a+1] << c; } else // if(j < 0) { j = -j; int a = j / 32; int b = j % 32; int c = 32 - b; int i; for(i = a; i < v.length; i++) bv.v[i] ^= v[i-a] << b; // la retenue for(i = a+1; i < v.length; i++) bv.v[i] ^= v[i-a-1] >>> c; } return bv; } /** * Shift all the bits of the current BitVector j * positions to the right if j is positive, and j positions * to the left if j is negative. * The new bits that appears to the left or to the rigth are set to 0. * Returns this. * * @param j the size of the shift * * @return this * */ public BitVector selfShift (int j) { if(j == 0) return this; else if(j > length || j < -length) { for(int i = 0; i < v.length; i++) v[i] = 0; } else if(j > 0) { int a = j / 32; int b = j % 32; int c = 32 - b; int i; for(i = 0; i+a+1 < v.length; i++) { v[i] = v[i+a] >>> b; // la retenue v[i] ^= v[i+a+1] << c; } v[i] = v[i+a] >>> b; for(i += 1; i < v.length; i++) v[i] = 0; } else // if(j < 0) { j = -j; int a = j / 32; int b = j % 32; int c = 32 - b; int i; for(i = v.length - 1; i > a; i--) { v[i] = v[i-a] << b; // la retenue v[i] ^= v[i-a-1] >>> c; } v[i] = v[i-a] << b; for(i -= 1; i >= 0; i--) v[i] = 0; } return this; } /** * Returns the scalar product of two BitVector's modulo 2. * It returns true if there is an odd number of bits with a value of 1 * in the result of the and operator applied on this and * that, and returns false otherwise. * * @param that the other BitVector with which to do the scalar product * * @return the scalar product * */ public boolean scalarProduct (BitVector that) { //we must take that is not longer than this if(that.v.length > this.v.length) return that.scalarProduct(this); boolean result = false; int prod; for(int i = 0; i < that.v.length; i++) { prod = this.v[i] & that.v[i]; while(prod != 0) { // a chaque iteration, on enleve le 1 le plus a droite prod &= prod - 1; result = !result; } } return result; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy