blob: ec5bafcdeaacb94fa4430e72a2b67e8f01f0948e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
package org.apache.commons.rng.core.source64;
import org.apache.commons.rng.core.util.NumberFactory;
import org.apache.commons.rng.core.BaseProvider;
/**
* Base class for all implementations that provide a {@code long}-based
* source randomness.
*/
public abstract class LongProvider
extends BaseProvider
implements RandomLongSource {
/** Empty boolean source. This is the location of the sign-bit after 63 right shifts on
* the boolean source. */
private static final long EMPTY_BOOL_SOURCE = 1;
/** Empty int source. This requires a negative value as the sign-bit is used to
* trigger a refill. */
private static final long EMPTY_INT_SOURCE = -1;
/**
* Provides a bit source for booleans.
*
* <p>A cached value from a call to {@link #next()}.
*
* <p>Only stores 63-bits when full as 1 bit has already been consumed.
* The sign bit is a flag that shifts down so the source eventually equals 1
* when all bits are consumed and will trigger a refill.
*/
private long booleanSource = EMPTY_BOOL_SOURCE;
/**
* Provides a source for ints.
*
* <p>A cached half-value value from a call to {@link #next()}.
* The int is stored in the lower 32 bits with zeros in the upper bits.
* When empty this is set to negative to trigger a refill.
*/
private long intSource = EMPTY_INT_SOURCE;
/**
* Creates a new instance.
*/
public LongProvider() {
super();
}
/**
* Creates a new instance copying the state from the source.
*
* <p>This provides base functionality to allow a generator to create a copy, for example
* for use in the {@link org.apache.commons.rng.JumpableUniformRandomProvider
* JumpableUniformRandomProvider} interface.
*
* @param source Source to copy.
* @since 1.3
*/
protected LongProvider(LongProvider source) {
booleanSource = source.booleanSource;
intSource = source.intSource;
}
/**
* Reset the cached state used in the default implementation of {@link #nextBoolean()}
* and {@link #nextInt()}.
*
* <p>This should be used when the state is no longer valid, for example after a jump
* performed for the {@link org.apache.commons.rng.JumpableUniformRandomProvider
* JumpableUniformRandomProvider} interface.</p>
*
* @since 1.3
*/
protected void resetCachedState() {
booleanSource = EMPTY_BOOL_SOURCE;
intSource = EMPTY_INT_SOURCE;
}
/** {@inheritDoc} */
@Override
protected byte[] getStateInternal() {
final long[] state = {booleanSource, intSource};
return composeStateInternal(NumberFactory.makeByteArray(state),
super.getStateInternal());
}
/** {@inheritDoc} */
@Override
protected void setStateInternal(byte[] s) {
final byte[][] c = splitStateInternal(s, 2 * Long.BYTES);
final long[] state = NumberFactory.makeLongArray(c[0]);
booleanSource = state[0];
intSource = state[1];
super.setStateInternal(c[1]);
}
/** {@inheritDoc} */
@Override
public long nextLong() {
return next();
}
/** {@inheritDoc} */
@Override
public int nextInt() {
long bits = intSource;
if (bits < 0) {
// Refill
bits = next();
// Store high 32 bits, return low 32 bits
intSource = bits >>> 32;
return (int) bits;
}
// Reset and return previous low bits
intSource = -1;
return (int) bits;
}
/** {@inheritDoc} */
@Override
public boolean nextBoolean() {
long bits = booleanSource;
if (bits == 1) {
// Refill
bits = next();
// Store a refill flag in the sign bit and the unused 63 bits, return lowest bit
booleanSource = Long.MIN_VALUE | (bits >>> 1);
return (bits & 0x1) == 1;
}
// Shift down eventually triggering refill, return current lowest bit
booleanSource = bits >>> 1;
return (bits & 0x1) == 1;
}
}