org.jenetics.internal.util.bit Maven / Gradle / Ivy
/*
* Java Genetic Algorithm Library (jenetics-3.8.0).
* Copyright (c) 2007-2017 Franz Wilhelmstötter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author:
* Franz Wilhelmstötter ([email protected])
*/
package org.jenetics.internal.util;
import static java.lang.Integer.parseInt;
import static java.lang.Math.min;
import org.jenetics.internal.math.random;
import org.jenetics.util.RandomRegistry;
/**
* Some bit utils. All operation assume
* little-endian byte order.
*
*
* Byte: 3 2 1 0
* | | | |
* Array: |11110011|10011101|01000000|00101010|
* | | | |
* Bit: 23 15 7 0
*
*
* @author Franz Wilhelmstötter
* @since 1.0
* @version 3.0
*/
public final class bit {
private bit() {require.noInstance();}
/**
* Lookup table for counting the number of set bits in a {@code byte} value.
*/
private static final byte[] BIT_SET_TABLE = {
(byte)1, (byte)2, (byte)2, (byte)3, (byte)2, (byte)3, (byte)3, (byte)4,
(byte)2, (byte)3, (byte)3, (byte)4, (byte)3, (byte)4, (byte)4, (byte)5,
(byte)2, (byte)3, (byte)3, (byte)4, (byte)3, (byte)4, (byte)4, (byte)5,
(byte)3, (byte)4, (byte)4, (byte)5, (byte)4, (byte)5, (byte)5, (byte)6,
(byte)2, (byte)3, (byte)3, (byte)4, (byte)3, (byte)4, (byte)4, (byte)5,
(byte)3, (byte)4, (byte)4, (byte)5, (byte)4, (byte)5, (byte)5, (byte)6,
(byte)3, (byte)4, (byte)4, (byte)5, (byte)4, (byte)5, (byte)5, (byte)6,
(byte)4, (byte)5, (byte)5, (byte)6, (byte)5, (byte)6, (byte)6, (byte)7,
(byte)2, (byte)3, (byte)3, (byte)4, (byte)3, (byte)4, (byte)4, (byte)5,
(byte)3, (byte)4, (byte)4, (byte)5, (byte)4, (byte)5, (byte)5, (byte)6,
(byte)3, (byte)4, (byte)4, (byte)5, (byte)4, (byte)5, (byte)5, (byte)6,
(byte)4, (byte)5, (byte)5, (byte)6, (byte)5, (byte)6, (byte)6, (byte)7,
(byte)3, (byte)4, (byte)4, (byte)5, (byte)4, (byte)5, (byte)5, (byte)6,
(byte)4, (byte)5, (byte)5, (byte)6, (byte)5, (byte)6, (byte)6, (byte)7,
(byte)4, (byte)5, (byte)5, (byte)6, (byte)5, (byte)6, (byte)6, (byte)7,
(byte)5, (byte)6, (byte)6, (byte)7, (byte)6, (byte)7, (byte)7, (byte)8,
(byte)0, (byte)1, (byte)1, (byte)2, (byte)1, (byte)2, (byte)2, (byte)3,
(byte)1, (byte)2, (byte)2, (byte)3, (byte)2, (byte)3, (byte)3, (byte)4,
(byte)1, (byte)2, (byte)2, (byte)3, (byte)2, (byte)3, (byte)3, (byte)4,
(byte)2, (byte)3, (byte)3, (byte)4, (byte)3, (byte)4, (byte)4, (byte)5,
(byte)1, (byte)2, (byte)2, (byte)3, (byte)2, (byte)3, (byte)3, (byte)4,
(byte)2, (byte)3, (byte)3, (byte)4, (byte)3, (byte)4, (byte)4, (byte)5,
(byte)2, (byte)3, (byte)3, (byte)4, (byte)3, (byte)4, (byte)4, (byte)5,
(byte)3, (byte)4, (byte)4, (byte)5, (byte)4, (byte)5, (byte)5, (byte)6,
(byte)1, (byte)2, (byte)2, (byte)3, (byte)2, (byte)3, (byte)3, (byte)4,
(byte)2, (byte)3, (byte)3, (byte)4, (byte)3, (byte)4, (byte)4, (byte)5,
(byte)2, (byte)3, (byte)3, (byte)4, (byte)3, (byte)4, (byte)4, (byte)5,
(byte)3, (byte)4, (byte)4, (byte)5, (byte)4, (byte)5, (byte)5, (byte)6,
(byte)2, (byte)3, (byte)3, (byte)4, (byte)3, (byte)4, (byte)4, (byte)5,
(byte)3, (byte)4, (byte)4, (byte)5, (byte)4, (byte)5, (byte)5, (byte)6,
(byte)3, (byte)4, (byte)4, (byte)5, (byte)4, (byte)5, (byte)5, (byte)6,
(byte)4, (byte)5, (byte)5, (byte)6, (byte)5, (byte)6, (byte)6, (byte)7
};
private static final int BIT_SET_TABLE_INDEX_OFFSET = 128;
/**
* Return the (boolean) value of the byte array at the given bit index.
*
* @param data the byte array.
* @param index the bit index.
* @return the value at the given bit index.
* @throws IndexOutOfBoundsException if the index is
* {@code index >= max || index < 0}.
* @throws NullPointerException if the {@code data} array is {@code null}.
*/
public static boolean get(final byte[] data, final int index) {
return (data[index >>> 3] & (1 << (index & 7))) != 0;
}
/**
* Set the bit in the given byte array at the bit position (not the index
* within the byte array) to the specified value.
*
* @param data the byte array.
* @param index the bit index within the byte array.
* @param value the value to set.
* @return the given data array.
* @throws IndexOutOfBoundsException if the index is
* {@code index >= max || index < 0}.
* @throws NullPointerException if the {@code data} array is {@code null}.
*/
public static byte[] set(
final byte[] data,
final int index,
final boolean value
) {
return value ? set(data, index) : unset(data, index);
}
/**
* Set the bit in the given byte array at the bit position (not the index
* within the byte array) to {@code true}.
*
* @param data the byte array.
* @param index the bit index within the byte array.
* @return the given data array.
* @throws IndexOutOfBoundsException if the index is
* {@code index >= max || index < 0}.
* @throws NullPointerException if the {@code data} array is {@code null}.
*/
public static byte[] set(final byte[] data, final int index) {
data[index >>> 3] |= 1 << (index & 7);
return data;
}
/**
* Set the bit in the given byte array at the bit position (not the index
* within the byte array) to {@code false}.
*
* @param data the byte array.
* @param index the bit index within the byte array.
* @return the given data array.
* @throws IndexOutOfBoundsException if the index is
* {@code index >= max || index < 0}.
* @throws NullPointerException if the {@code data} array is {@code null}.
*/
public static byte[] unset(final byte[] data, final int index) {
data[index >>> 3] &= ~(1 << (index & 7));
return data;
}
/**
* Swap a given range with a range of the same size with another array.
*
*
* start end
* | |
* data: +---+---+---+---+---+---+---+---+---+---+---+---+
* +---------------+
* +---------------+
* otherData: +---+---+---+---+---+---+---+---+---+---+---+---+
* |
* otherStart
*
*
* @param data the first byte array which are used for swapping.
* @param start the start bit index of the {@code data} byte array,
* inclusively.
* @param end the end bit index of the {@code data} byte array, exclusively.
* @param otherData the other byte array to swap the elements with.
* @param otherStart the start index of the {@code otherData} byte array.
* @throws IndexOutOfBoundsException if {@code start > end} or
* if {@code start < 0 || end >= data.length*8 || otherStart < 0 ||
* otherStart + (end - start) >= otherData.length*8}
*/
public static void swap(
final byte[] data, final int start, final int end,
final byte[] otherData, final int otherStart
) {
for (int i = end - start; --i >= 0;) {
final boolean temp = get(data, i + start);
set(data, i + start, get(otherData, otherStart + i));
set(otherData, otherStart + i, temp);
}
}
/**
* Returns the number of one-bits in the given {@code byte} array.
*
* @param data the {@code byte} array for which the one bits should be
* counted.
* @return the number of one bits in the given {@code byte} array.
*/
public static int count(final byte[] data) {
int count = 0;
for (int i = data.length; --i >= 0;) {
count += count(data[i]);
}
return count;
}
/**
* Returns the number of one-bits in the given {@code byte} {@code value}.
*
* @param value the value for which the one bits should be counted.
* @return the number of one bits in the given value
*/
public static int count(final byte value) {
return BIT_SET_TABLE[value + BIT_SET_TABLE_INDEX_OFFSET];
}
/**
* Shifting all bits in the given {@code data} array the given
* {@code shift} to the right. The bits on the left side are filled with
* zeros.
*
* @param data the data bits to shift.
* @param shift the number of bits to shift.
* @return the given {@code data} array.
* @throws NullPointerException if the {@code data} array is {@code null}.
*/
public static byte[] shiftRight(final byte[] data, final int shift) {
final int bytes = min(shift >>> 3, data.length);
final int bits = shift & 7;
if (bytes > 0) {
for (int i = 0, n = data.length - bytes; i < n; ++i) {
data[i] = data[i + bytes];
}
for (int i = data.length, n = data.length - bytes; --i >= n;) {
data[i] = (byte)0;
}
}
if (bits > 0 && bytes < data.length) {
int carry = 0;
int nextCarry = 0;
for (int i = data.length; --i >= 0;) {
int d = data[i] & 0xFF;
nextCarry = d << (Byte.SIZE - bits);
d >>>= bits;
d |= carry;
data[i] = (byte)(d & 0xFF);
carry = nextCarry;
}
}
return data;
}
/**
* Shifting all bits in the given {@code data} array the given
* {@code shift} to the left. The bits on the right side are filled with
* zeros.
*
* @param data the data bits to shift.
* @param shift the number of bits to shift.
* @return the given {@code data} array.
* @throws NullPointerException if the {@code data} array is {@code null}.
*/
public static byte[] shiftLeft(final byte[] data, final int shift) {
final int bytes = min(shift >>> 3, data.length);
final int bits = shift & 7;
if (bytes > 0) {
for (int i = 0, n = data.length - bytes; i < n; ++i) {
data[data.length - 1 - i] = data[data.length - 1 - i - bytes];
}
for (int i = 0; i < bytes; ++i) {
data[i] = (byte)0;
}
}
if (bits > 0 && bytes < data.length) {
int carry = 0;
int nextCarry = 0;
for (int i = bytes; i < data.length; ++i) {
int d = data[i] & 0xFF;
nextCarry = d >>> (Byte.SIZE - bits);
d <<= bits;
d |= carry;
data[i] = (byte)(d & 0xFF);
carry = nextCarry;
}
}
return data;
}
/**
* Increment the given {@code data} array.
*
* @param data the given {@code data} array.
* @return the given {@code data} array.
* @throws NullPointerException if the {@code data} array is {@code null}.
*/
public static byte[] increment(final byte[] data) {
boolean carry = true;
for (int i = 0; i < data.length && carry; ++i) {
data[i] = (byte)(data[i] + 1);
carry = data[i] > 0xFF;
}
return data;
}
/**
* Invert the given {@code data} array.
*
* @param data the given {@code data} array.
* @return the given {@code data} array.
* @throws NullPointerException if the {@code data} array is {@code null}.
*/
public static byte[] invert(final byte[] data) {
for (int i = data.length; --i >= 0;) {
data[i] = (byte)~data[i];
}
return data;
}
/**
* Make the two's complement of the given {@code data} array.
*
* @param data the given {@code data} array.
* @return the given {@code data} array.
* @throws NullPointerException if the {@code data} array is {@code null}.
*/
public static byte[] complement(final byte[] data) {
return increment(invert(data));
}
/**
* Flip the bit at the given index.
*
* @param data the data array.
* @param index the index of the bit to flip.
* @return the input array, for command chaining
* @throws IndexOutOfBoundsException if the index is
* {@code index >= max || index < 0}.
* @throws NullPointerException if the {@code data} array is {@code null}.
*/
public static byte[] flip(final byte[] data, final int index) {
return get(data, index) ? unset(data, index) : set(data, index);
}
public static byte[] reverse(final byte[] array) {
int i = 0;
int j = array.length;
while (i < j) {
swap(array, i++, --j);
}
return array;
}
private static void swap(final byte[] array, final int i, final int j) {
final byte temp = array[i];
array[i] = array[j];
array[j] = temp;
}
/**
* Copies the specified range of the specified array into a new array.
*
* @param data the bits from which a range is to be copied
* @param start the initial index of the range to be copied, inclusive
* @param end the final index of the range to be copied, exclusive.
* @return a new array containing the specified range from the original array
* @throws ArrayIndexOutOfBoundsException if start < 0 or
* start > data.length*8
* @throws IllegalArgumentException if start > end
* @throws NullPointerException if the {@code data} array is
* {@code null}.
*/
public static byte[] copy(final byte[] data, final int start, final int end) {
if (start > end) {
throw new IllegalArgumentException(String.format(
"start > end: %d > %d", start, end
));
}
if (start < 0 || start > data.length << 3) {
throw new ArrayIndexOutOfBoundsException(String.format(
"%d < 0 || %d > %d", start, start, data.length*8
));
}
final int to = min(data.length << 3, end);
final int byteStart = start >>> 3;
final int bitStart = start & 7;
final int bitLength = to - start;
final byte[] copy = new byte[toByteLength(to - start)];
if (copy.length > 0) {
// Perform the byte wise right shift.
System.arraycopy(data, byteStart, copy, 0, copy.length);
// Do the remaining bit wise right shift.
shiftRight(copy, bitStart);
// Add the 'lost' bits from the next byte, if available.
if (data.length > copy.length + byteStart) {
copy[copy.length - 1] |= (byte)(data[byteStart + copy.length]
<< (Byte.SIZE - bitStart));
}
// Trim (delete) the overhanging bits.
copy[copy.length - 1] &= 0xFF >>> ((copy.length << 3) - bitLength);
}
return copy;
}
public static boolean getAndSet(final byte[] array, final int index) {
final boolean result = get(array, index);
set(array, index);
return result;
}
/**
* Convert a binary representation of the given byte array to a string. The
* string has the following format:
*
* Byte: 3 2 1 0
* | | | |
* Array: "11110011|10011101|01000000|00101010"
* | | | |
* Bit: 23 15 7 0
*
* Only the array string is printed.
*
* @see #fromByteString(String)
*
* @param data the byte array to convert to a string.
* @return the binary representation of the given byte array.
*/
public static String toByteString(final byte... data) {
final StringBuilder out = new StringBuilder();
if (data.length > 0) {
for (int j = 7; j >= 0; --j) {
out.append((data[data.length - 1] >>> j) & 1);
}
}
for (int i = data.length - 2; i >= 0 ;--i) {
out.append('|');
for (int j = 7; j >= 0; --j) {
out.append((data[i] >>> j) & 1);
}
}
return out.toString();
}
/**
* Convert a string which was created with the {@link #toByteString(byte...)}
* method back to an byte array.
*
* @see #toByteString(byte...)
*
* @param data the string to convert.
* @return the byte array.
* @throws IllegalArgumentException if the given data string could not be
* converted.
*/
public static byte[] fromByteString(final String data) {
final String[] parts = data.split("\\|");
final byte[] bytes = new byte[parts.length];
for (int i = 0; i < parts.length; ++i) {
if (parts[i].length() != Byte.SIZE) {
throw new IllegalArgumentException(
"Byte value doesn't contain 8 bit: " + parts[i]
);
}
try {
bytes[parts.length - 1 - i] = (byte)parseInt(parts[i], 2);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(e);
}
}
return bytes;
}
/**
* Create a new {@code byte[]} array which can store at least the number
* of bits as defined by the given {@code length} parameter.
*
* @param length the number of bits, the returned byte array can store.
* @return the new byte array.s
*/
public static byte[] newArray(final int length) {
return new byte[toByteLength(length)];
}
/**
* Create a new {@code byte[]} array which can store at least the number
* of bits as defined by the given {@code length} parameter. The returned
* byte array is initialized with ones according to the given ones
* probability {@code p}.
*
* @param length the number of bits, the returned byte array can store.
* @param p the ones probability of the returned byte array.
* @return the new byte array.s
* @throws IllegalArgumentException if {@code p} is not a valid probability.
*/
public static byte[] newArray(final int length, final double p) {
final byte[] bytes = newArray(length);
random.indexes(RandomRegistry.getRandom(), length, p)
.forEach(i -> bytes[i >>> 3] |= 1 << (i & 7));
return bytes;
}
/**
* Return the minimum number of bytes to store the given number of bits.
*
* @param bitLength the number of bits
* @return the number of bytes needed to store the given number of bits.
*/
public static int toByteLength(final int bitLength) {
return (bitLength & 7) == 0 ? (bitLength >>> 3) : (bitLength >>> 3) + 1;
}
public static long toLong(final byte[] data) {
return
((long)data[0] << 56) +
((long)(data[1] & 255) << 48) +
((long)(data[2] & 255) << 40) +
((long)(data[3] & 255) << 32) +
((long)(data[4] & 255) << 24) +
((data[5] & 255) << 16) +
((data[6] & 255) << 8) +
(data[7] & 255);
}
public static byte[] toBytes(final long value) {
final byte[] bytes = new byte[8];
bytes[0] = (byte)(value >>> 56);
bytes[1] = (byte)(value >>> 48);
bytes[2] = (byte)(value >>> 40);
bytes[3] = (byte)(value >>> 32);
bytes[4] = (byte)(value >>> 24);
bytes[5] = (byte)(value >>> 16);
bytes[6] = (byte)(value >>> 8);
bytes[7] = (byte) value;
return bytes;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy