src.it.unimi.dsi.bits.Fast Maven / Gradle / Ivy
package it.unimi.dsi.bits;
/*
* DSI utilities
*
* Copyright (C) 2007-2017 Sebastiano Vigna
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option)
* any later version.
*
* This library 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, see .
*
*/
/** All-purpose optimised bit-fiddling static-method container class.
*
* This class used to contain a large number of bits hacks. Intrinsification of methods
* such as {@link Long#bitCount(long)}, {@link Long#numberOfTrailingZeros(long)}, etc. using
* SSE instructions has made such hacks obsolete.
*
*
The main highlight is now a new algorithm for {@linkplain #select(long, int) selection} that is twice as
* fast as the one previously implemented, but that will behave impredictably if there is no bit with the requested rank; the
* algorithm is based on the one presented
* by Sebastiano Vigna in “Broadword Implementation of Rank/Select Queries”,
* Proc. of the 7th International Workshop on Experimental Algorithms, WEA 2008,
* number 5038 in Lecture Notes in Computer Science, pages 154−168. Springer–Verlag, 2008, but it
* has been improved with ideas from Simon Gog's SDSL library.
*
* @author Sebastiano Vigna
* @since 0.1
*/
public final class Fast {
private Fast() {}
public static final long ONES_STEP_4 = 0x1111111111111111L;
public static final long ONES_STEP_8 = 0x0101010101010101L;
public static final long MSBS_STEP_8 = 0x80L * ONES_STEP_8;
@Deprecated
public static final long INCR_STEP_8 = 0x80L << 56 | 0x40L << 48 | 0x20L << 40 | 0x10L << 32 | 0x8L << 24 | 0x4L << 16 | 0x2L << 8 | 0x1;
/** Precomputed least significant bits for bytes (-1 for 0). */
public static final int[] BYTELSB = {
-1, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
};
/** Precomputed most significant bits for bytes (-1 for 0). */
public static final int[] BYTEMSB = {
-1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
};
/** A precomputed table containing in position 256i + j the position of the i-th one (0 ≤ j < 8) in the binary representation of i
* (0 ≤ i < 256), or -1 if no such bit exists. */
public static final byte[] selectInByte = {
-1, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, -1, -1, -1, 1, -1, 2, 2, 1, -1, 3, 3, 1, 3, 2, 2, 1, -1, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, -1, 5, 5, 1, 5, 2, 2, 1, 5, 3, 3, 1, 3, 2, 2, 1, 5, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, -1, 6, 6, 1, 6, 2, 2, 1, 6, 3, 3, 1, 3, 2, 2, 1, 6, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, 6, 5, 5, 1, 5, 2, 2, 1, 5, 3, 3, 1, 3, 2, 2, 1, 5, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, -1, 7, 7, 1, 7, 2, 2, 1, 7, 3, 3, 1, 3, 2, 2, 1, 7, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, 7, 5, 5, 1, 5, 2, 2, 1, 5, 3, 3, 1, 3, 2, 2, 1, 5, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, 7, 6, 6, 1, 6, 2, 2, 1, 6, 3, 3, 1, 3, 2, 2, 1, 6, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, 6, 5, 5, 1, 5, 2, 2, 1, 5, 3, 3, 1, 3, 2, 2, 1, 5, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, 3, -1, 3, 3, 2, -1, -1, -1, 4, -1, 4, 4, 2, -1, 4, 4, 3, 4, 3, 3, 2, -1, -1, -1, 5, -1, 5, 5, 2, -1, 5, 5, 3, 5, 3, 3, 2, -1, 5, 5, 4, 5, 4, 4, 2, 5, 4, 4, 3, 4, 3, 3, 2, -1, -1, -1, 6, -1, 6, 6, 2, -1, 6, 6, 3, 6, 3, 3, 2, -1, 6, 6, 4, 6, 4, 4, 2, 6, 4, 4, 3, 4, 3, 3, 2, -1, 6, 6, 5, 6, 5, 5, 2, 6, 5, 5, 3, 5, 3, 3, 2, 6, 5, 5, 4, 5, 4, 4, 2, 5, 4, 4, 3, 4, 3, 3, 2, -1, -1, -1, 7, -1, 7, 7, 2, -1, 7, 7, 3, 7, 3, 3, 2, -1, 7, 7, 4, 7, 4, 4, 2, 7, 4, 4, 3, 4, 3, 3, 2, -1, 7, 7, 5, 7, 5, 5, 2, 7, 5, 5, 3, 5, 3, 3, 2, 7, 5, 5, 4, 5, 4, 4, 2, 5, 4, 4, 3, 4, 3, 3, 2, -1, 7, 7, 6, 7, 6, 6, 2, 7, 6, 6, 3, 6, 3, 3, 2, 7, 6, 6, 4, 6, 4, 4, 2, 6, 4, 4, 3, 4, 3, 3, 2, 7, 6, 6, 5, 6, 5, 5, 2, 6, 5, 5, 3, 5, 3, 3, 2, 6, 5, 5, 4, 5, 4, 4, 2, 5, 4, 4, 3, 4, 3, 3, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, 4, -1, 4, 4, 3, -1, -1, -1, -1, -1, -1, -1, 5, -1, -1, -1, 5, -1, 5, 5, 3, -1, -1, -1, 5, -1, 5, 5, 4, -1, 5, 5, 4, 5, 4, 4, 3, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1, -1, 6, -1, 6, 6, 3, -1, -1, -1, 6, -1, 6, 6, 4, -1, 6, 6, 4, 6, 4, 4, 3, -1, -1, -1, 6, -1, 6, 6, 5, -1, 6, 6, 5, 6, 5, 5, 3, -1, 6, 6, 5, 6, 5, 5, 4, 6, 5, 5, 4, 5, 4, 4, 3, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, 7, -1, 7, 7, 3, -1, -1, -1, 7, -1, 7, 7, 4, -1, 7, 7, 4, 7, 4, 4, 3, -1, -1, -1, 7, -1, 7, 7, 5, -1, 7, 7, 5, 7, 5, 5, 3, -1, 7, 7, 5, 7, 5, 5, 4, 7, 5, 5, 4, 5, 4, 4, 3, -1, -1, -1, 7, -1, 7, 7, 6, -1, 7, 7, 6, 7, 6, 6, 3, -1, 7, 7, 6, 7, 6, 6, 4, 7, 6, 6, 4, 6, 4, 4, 3, -1, 7, 7, 6, 7, 6, 6, 5, 7, 6, 6, 5, 6, 5, 5, 3, 7, 6, 6, 5, 6, 5, 5, 4, 6, 5, 5, 4, 5, 4, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, -1, -1, -1, -1, -1, -1, -1, 5, -1, -1, -1, 5, -1, 5, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1, -1, 6, -1, 6, 6, 4, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1, -1, 6, -1, 6, 6, 5, -1, -1, -1, 6, -1, 6, 6, 5, -1, 6, 6, 5, 6, 5, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, 7, -1, 7, 7, 4, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, 7, -1, 7, 7, 5, -1, -1, -1, 7, -1, 7, 7, 5, -1, 7, 7, 5, 7, 5, 5, 4, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, 7, -1, 7, 7, 6, -1, -1, -1, 7, -1, 7, 7, 6, -1, 7, 7, 6, 7, 6, 6, 4, -1, -1, -1, 7, -1, 7, 7, 6, -1, 7, 7, 6, 7, 6, 6, 5, -1, 7, 7, 6, 7, 6, 6, 5, 7, 6, 6, 5, 6, 5, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1, -1, 6, -1, 6, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, 7, -1, 7, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, 7, -1, 7, 7, 6, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, 7, -1, 7, 7, 6, -1, -1, -1, 7, -1, 7, 7, 6, -1, 7, 7, 6, 7, 6, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, 7, -1, 7, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7
};
/** Maps integers bijectively into natural numbers.
*
*
This method will map a negative integer x to -2x-1 and
* a nonnegative integer x to 2x. It can be used to save
* integers in the range [{@link Integer#MIN_VALUE}/2..{@link Integer#MAX_VALUE}/2]
* (i.e., [-230..230-1])
* using the standard coding methods (which all work on natural numbers). Note
* that no range checks are performed.
*
*
The inverse of the above map is computed by {@link #nat2int(int)}.
*
* @param x an integer.
* @return the argument mapped into a natural number.
* @see #nat2int(int)
*/
public static int int2nat(final int x) {
return x >= 0 ? x << 1 : -((x << 1) + 1);
}
/** Maps natural numbers bijectively into integers.
*
*
This method computes the inverse of {@link #int2nat(int)}.
*
* @param x a natural number.
* @return the argument mapped into an integer.
* @see #int2nat(int)
*/
public static int nat2int(final int x) {
return x % 2 == 0 ? x >> 1 : -(x >> 1) - 1;
}
/** Maps longs bijectively into long natural numbers.
*
*
This method will map a negative long x to -2x-1 and
* a nonnegative long x to 2x. It can be used to save
* longs in the range [{@link Long#MIN_VALUE}/2..{@link Long#MAX_VALUE}/2]
* (i.e., [-262..262-1])
* using the standard coding methods (which all work on natural numbers). Note
* that no range checks are performed.
*
*
The inverse of the above map is computed by {@link #nat2int(long)}.
*
* @param x a long.
* @return the argument mapped into a long natural number.
* @see #int2nat(int)
*/
public static long int2nat(final long x) {
return x >= 0 ? x << 1 : -((x << 1) + 1);
}
/** Maps long natural numbers bijectively into longs.
*
*
This method computes the inverse of {@link #int2nat(long)}.
*
* @param x a long natural number.
* @return the argument mapped into a long.
* @see #nat2int(int)
*/
public static long nat2int(final long x) {
return x % 2 == 0 ? x >> 1 : -(x >> 1) - 1;
}
/** Returns the base-two logarithm of the argument.
*
* @param x a double.
* @return the base-2 logarithm of x
.
*/
public static double log2(final double x) {
return Math.log(x) / 0.6931471805599453;
}
/** Computes the ceiling of the base-two logarithm of the argument.
*
*
This method relies on {@link #mostSignificantBit(int)}, and thus is pretty fast.
*
* @param x an integer.
* @return the ceiling of the base-two logarithm of the argument, or -1 if x
is zero.
*/
public static int ceilLog2(final int x) {
if (x <= 2) return x - 1;
return Integer.SIZE - Integer.numberOfLeadingZeros(x - 1);
}
/** Computes the ceiling of the base-two logarithm of the argument.
*
*
This method relies on {@link #mostSignificantBit(long)}, and thus is pretty fast.
*
* @param x an integer.
* @return the ceiling of the base-two logarithm of the argument, or -1 if x
is zero.
*/
public static int ceilLog2(final long x) {
if (x <= 2) return (int)(x - 1);
return Long.SIZE - Long.numberOfLeadingZeros(x - 1);
}
/** Computes an approximate integer base-2 logarithm of the argument.
*
*
This method relies on {@link Double#doubleToRawLongBits(double)}, and thus is very
* fast if the former is intrinsified by the JVM.
*
* @param x a double.
* @return an integer approximation of the base-two logarithm of the argument.
*/
public static int approximateLog2(final double x) {
final long bits = Double.doubleToRawLongBits(x);
// The exponent is corrected by one if the first significand digits are big enough.
return (int)((bits >>> 52) & 0x7FF) - 1023 + ((bits >>> 48 & 0xF) > 6 ? 1 : 0);
}
/** Quickly raises 2 to the argument.
*
* @param exponent an integer exponent between -62 ad 62.
* @return 2exponent
.
*/
public static double pow2(final int exponent) {
//return fixedValues[approximate + (1 << EXPONENT_BITS) - ADJUSTMENT - 1];
if (exponent < 0) return 1. / (1L << -exponent);
return 1L << exponent;
}
/** Returns the number of bits that are necessary to encode the argument.
*
* @param x an integer.
* @return the number of bits that are necessary to encode x
.
*/
public static int length(final int x) {
return x == 0 ? 1 : mostSignificantBit(x) + 1;
}
/** Returns the number of bits that are necessary to encode the argument.
*
* @param x a long.
* @return the number of bits that are necessary to encode x
.
*/
public static int length(final long x) {
return x == 0 ? 1 : mostSignificantBit(x) + 1;
}
private static int selectBroadword(final long x, final int rank) {
// Phase 1: sums by byte
long byteSums = x - ((x & 0xa * ONES_STEP_4) >>> 1);
byteSums = (byteSums & 3 * ONES_STEP_4) + ((byteSums >>> 2) & 3 * ONES_STEP_4);
byteSums = (byteSums + (byteSums >>> 4)) & 0x0f * ONES_STEP_8;
byteSums *= ONES_STEP_8;
// Phase 2: compare each byte sum with rank to obtain the relevant byte
final long rankStep8 = rank * ONES_STEP_8;
final long byteOffset = (((((rankStep8 | MSBS_STEP_8) - byteSums) & MSBS_STEP_8) >>> 7) * ONES_STEP_8 >>> 53) & ~0x7;
// Phase 3: Locate the relevant byte and make 8 copies with incremental masks
final int byteRank = (int)(rank - (((byteSums << 8) >>> byteOffset) & 0xFF));
final long spreadBits = (x >>> byteOffset & 0xFF) * ONES_STEP_8 & INCR_STEP_8;
final long bitSums = (((spreadBits | ((spreadBits | MSBS_STEP_8) - ONES_STEP_8)) & MSBS_STEP_8) >>> 7) * ONES_STEP_8;
// Compute the inside-byte location and return the sum
final long byteRankStep8 = byteRank * ONES_STEP_8;
return (int)(byteOffset + (((((byteRankStep8 | MSBS_STEP_8) - bitSums) & MSBS_STEP_8) >>> 7) * ONES_STEP_8 >>> 56));
}
private final static long overflow[] = {
0x7f7f7f7f7f7f7f7fL,
0x7e7e7e7e7e7e7e7eL,
0x7d7d7d7d7d7d7d7dL,
0x7c7c7c7c7c7c7c7cL,
0x7b7b7b7b7b7b7b7bL,
0x7a7a7a7a7a7a7a7aL,
0x7979797979797979L,
0x7878787878787878L,
0x7777777777777777L,
0x7676767676767676L,
0x7575757575757575L,
0x7474747474747474L,
0x7373737373737373L,
0x7272727272727272L,
0x7171717171717171L,
0x7070707070707070L,
0x6f6f6f6f6f6f6f6fL,
0x6e6e6e6e6e6e6e6eL,
0x6d6d6d6d6d6d6d6dL,
0x6c6c6c6c6c6c6c6cL,
0x6b6b6b6b6b6b6b6bL,
0x6a6a6a6a6a6a6a6aL,
0x6969696969696969L,
0x6868686868686868L,
0x6767676767676767L,
0x6666666666666666L,
0x6565656565656565L,
0x6464646464646464L,
0x6363636363636363L,
0x6262626262626262L,
0x6161616161616161L,
0x6060606060606060L,
0x5f5f5f5f5f5f5f5fL,
0x5e5e5e5e5e5e5e5eL,
0x5d5d5d5d5d5d5d5dL,
0x5c5c5c5c5c5c5c5cL,
0x5b5b5b5b5b5b5b5bL,
0x5a5a5a5a5a5a5a5aL,
0x5959595959595959L,
0x5858585858585858L,
0x5757575757575757L,
0x5656565656565656L,
0x5555555555555555L,
0x5454545454545454L,
0x5353535353535353L,
0x5252525252525252L,
0x5151515151515151L,
0x5050505050505050L,
0x4f4f4f4f4f4f4f4fL,
0x4e4e4e4e4e4e4e4eL,
0x4d4d4d4d4d4d4d4dL,
0x4c4c4c4c4c4c4c4cL,
0x4b4b4b4b4b4b4b4bL,
0x4a4a4a4a4a4a4a4aL,
0x4949494949494949L,
0x4848484848484848L,
0x4747474747474747L,
0x4646464646464646L,
0x4545454545454545L,
0x4444444444444444L,
0x4343434343434343L,
0x4242424242424242L,
0x4141414141414141L,
0x4040404040404040L
};
private static int selectGogPetri(final long x, final int rank) {
assert rank < Long.bitCount(x);
// Phase 1: sums by byte
long byteSums = x - ((x >>> 1) & 0x5 * ONES_STEP_4);
byteSums = (byteSums & 3 * ONES_STEP_4) + ((byteSums >>> 2) & 3 * ONES_STEP_4);
byteSums = (byteSums + (byteSums >>> 4)) & 0x0f * ONES_STEP_8;
byteSums *= ONES_STEP_8;
// Phase 2: compare each byte sum with rank to obtain the relevant byte
final int byteOffset = (Long.numberOfTrailingZeros(byteSums + overflow[rank] & 0x8080808080808080L) >> 3) << 3;
return byteOffset + selectInByte[(int)(x >>> byteOffset & 0xFF) | (int)(rank - (((byteSums << 8) >>> byteOffset) & 0xFF)) << 8];
}
/** Returns the position of a bit of given rank (starting from zero).
*
* @param x a long.
* @param rank an integer smaller than the number of ones in {@code x}; impredictable
* results (including exceptions) might happen if this constraint is violated.
* @return the position in x
of the bit of given rank.
*/
public static int select(final long x, final int rank) {
assert rank < Long.bitCount(x);
// Phase 1: sums by byte
long byteSums = x - ((x >>> 1) & 0x5 * ONES_STEP_4);
byteSums = (byteSums & 3 * ONES_STEP_4) + ((byteSums >>> 2) & 3 * ONES_STEP_4);
byteSums = (byteSums + (byteSums >>> 4)) & 0x0f * ONES_STEP_8;
byteSums *= ONES_STEP_8;
// Phase 2: compare each byte sum with rank to obtain the relevant byte
final int byteOffset = Long.bitCount(((rank * ONES_STEP_8 | MSBS_STEP_8) - byteSums) & MSBS_STEP_8) << 3;
return byteOffset + selectInByte[(int)(x >>> byteOffset & 0xFF) | (int)(rank - (((byteSums << 8) >>> byteOffset) & 0xFF)) << 8];
}
/** Returns the most significant bit of a long.
*
*
This method returns 63 − {@link Long#numberOfLeadingZeros(long) Long.numberOfLeadingZeroes(x)}.
*
* @param x a long.
* @return the most significant bit of x
, of x
is nonzero; −1, otherwise.
*/
public static int mostSignificantBit(final long x) {
return 63 - Long.numberOfLeadingZeros(x);
}
/** Returns the most significant bit of an integer.
*
* @param x an integer.
* @return the most significant bit of x
, of x
is nonzero; −1, otherwise.
* @see #mostSignificantBit(long)
*/
public static int mostSignificantBit(final int x) {
return 31 - Integer.numberOfLeadingZeros(x);
}
public static void main(final String a[]) {
final long n = Long.parseLong(a[0]);
long start, elapsed;
long w = 0xFFFFFFFFFFFFFFFFL;
int x = 0;
for(int k = 10; k-- !=0;) {
System.out.print("Broadword select (new): ");
start = System.nanoTime();
for(long i = n; i-- != 0;) x ^= Fast.select(w, (int)(i & 63));
elapsed = System.nanoTime() - start;
System.out.println("elapsed " + elapsed + ", " + (double)elapsed / n + " ns/call");
System.out.print("Broadword select (Gog & Petri): ");
start = System.nanoTime();
for(long i = n; i-- != 0;) x ^= Fast.selectGogPetri(w, (int)(i & 63));
elapsed = System.nanoTime() - start;
System.out.println("elapsed " + elapsed + ", " + (double)elapsed / n + " ns/call");
System.out.print("Broadword select (old): ");
start = System.nanoTime();
for(long i = n; i-- != 0;) x ^= Fast.selectBroadword(w, (int)(i & 63));
elapsed = System.nanoTime() - start;
System.out.println("elapsed " + elapsed + ", " + (double)elapsed / n + " ns/call");
}
if (x == 0) System.out.println(0);
}
}