squidpony.squidmath.NumberTools Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of squidlib-util Show documentation
Show all versions of squidlib-util Show documentation
SquidLib platform-independent logic and utility code. Please refer to
https://github.com/SquidPony/SquidLib .
package squidpony.squidmath;
/**
* Various numeric functions that are important to performance but need alternate implementations on GWT to obtain it.
* Super-sourced on GWT, but most things here are direct calls to JDK methods when on desktop or Android.
* Some of this code makes use of "creative" bit manipulation of floats and doubles, which can sometimes allow uncommon
* input-to-output patterns (as in {@link #bounce(float)}), or even can yield a performance boost (compare
* {@link #zigzag(float)} to using modulus to accomplish the same results). The bit manipulation has good performance on
* GWT thanks to JS typed arrays, which are well-supported now across all recent browsers and have fallbacks in GWT in
* the unlikely event of a browser not supporting them.
*/
public final class NumberTools {
/**
* Identical to {@link Double#doubleToLongBits(double)} on desktop; optimized on GWT. When compiling to JS via GWT,
* there is no way to distinguish NaN values with different bits but that are still NaN, so this doesn't try to
* somehow permit that. Uses JS typed arrays on GWT, which are well-supported now across all recent browsers and
* have fallbacks in GWT in the unlikely event of a browser not supporting them. JS typed arrays support double, but
* not long, so this needs to compose a long from two ints, which means the double-to/from-long conversions aren't
* as fast as float-to/from-int conversions.
* @param value a {@code double} floating-point number.
* @return the bits that represent the floating-point number.
*/
public static long doubleToLongBits(final double value)
{
return Double.doubleToLongBits(value);
}
/**
* Identical to {@link Double#doubleToLongBits(double)} on desktop (note, not
* {@link Double#doubleToRawLongBits(double)}); optimized on GWT. When compiling to JS via GWT, there is no way to
* distinguish NaN values with different bits but that are still NaN, so this doesn't try to somehow permit that.
* Uses JS typed arrays on GWT, which are well-supported now across all recent browsers and have fallbacks in GWT in
* the unlikely event of a browser not supporting them. JS typed arrays support double, but not long, so this needs
* to compose a long from two ints, which means the double-to/from-long conversions aren't as fast as
* float-to/from-int conversions.
* @param value a {@code double} floating-point number.
* @return the bits that represent the floating-point number.
*/
public static long doubleToRawLongBits(final double value)
{
return Double.doubleToLongBits(value);
}
/**
* Identical to {@link Double#longBitsToDouble(long)} on desktop; optimized on GWT. Uses JS typed arrays on GWT,
* which are well-supported now across all recent browsers and have fallbacks in GWT in the unlikely event of a
* browser not supporting them. JS typed arrays support double, but not long, so this needs to compose a long from
* two ints, which means the double-to/from-long conversions aren't as fast as float-to/from-int conversions.
* @param bits a long.
* @return the {@code double} floating-point value with the same bit pattern.
*/
public static double longBitsToDouble(final long bits)
{
return Double.longBitsToDouble(bits);
}
/**
* Converts {@code value} to a long and gets the lower 32 bits of that long, as an int.
* @param value a {@code double} precision floating-point number.
* @return the lower half of the bits that represent the floating-point number, as an int.
*/
public static int doubleToLowIntBits(final double value)
{
return (int)(Double.doubleToLongBits(value) & 0xffffffffL);
}
/**
* Converts {@code value} to a long and gets the upper 32 bits of that long, as an int.
* @param value a {@code double} precision floating-point number.
* @return the upper half of the bits that represent the floating-point number, as an int.
*/
public static int doubleToHighIntBits(final double value)
{
return (int)(Double.doubleToLongBits(value) >>> 32);
}
/**
* Converts {@code value} to a long and gets the XOR of its upper and lower 32-bit sections. Useful for numerical
* code where a 64-bit double needs to be reduced to a 32-bit value with some hope of keeping different doubles
* giving different ints.
* @param value a {@code double} precision floating-point number.
* @return the XOR of the lower and upper halves of the bits that represent the floating-point number.
*/
public static int doubleToMixedIntBits(final double value)
{
final long l = Double.doubleToLongBits(value);
return (int)(l & 0xFFFFFFFFL) ^ (int)(l >>> 32);
}
/**
* Makes a modified version of value that uses the specified bits (up to 12) for its exponent and sign.
* Meant for some specific cases, like adjusting the exponent on an unknown double to the 1.0 to 2.0 range (which
* would pass 0x3ff for exponentBits). If you have a double from 1.0 to 2.0, you can subtract 1.0 from it to get the
* often-desirable 0.0-1.0 range. Other common cases are 0x400, which adjusts to between 2.0 and 4.0 (subtracting
* 3.0 from this gives the -1.0 to 1.0 range, useful for noise), and 0xBFF, which adjusts to between -2.0 and -1.0.
* For the last case, you might think that -0x3ff would work, but sadly it doesn't. You can use
* {@code exponentBits |= 0x800} to set the sign bit to negative, or {@code exponentBits &= 0x7ff} for positive.
* @param value a double that will have its sign and exponent set to the specified bits
* @param exponentBits the bits to use for the sign and exponent section of the returned modification of value
* @return the double produced by keeping the significand of value but changing its exponent and sign as given
*/
public static double setExponent(final double value, final int exponentBits)
{
return Double.longBitsToDouble((Double.doubleToLongBits(value) & 0xfffffffffffffL) | ((long) exponentBits << 52));
}
/**
* Gets an 8-bit section of the given double {@code value}, using {@code whichByte} to select whether this should
* return byte 0 (least significant), 1, 2, and so on up to 7 (most significant).
* @param value a float
* @param whichByte an int that will be used to select the byte to take from value (any int is allowed, only the bottom 3 bits are used to select)
* @return the selected byte from the given float
*/
public static byte getSelectedByte(final double value, final int whichByte)
{
return (byte)(Double.doubleToLongBits(value) >>> ((whichByte & 7) << 3));
}
/**
* Like {@link #getSelectedByte(double, int)}, this sets the byte at a selected position in the int representation of
* a double, then returns the double produced by the bit change. Uses {@code whichByte} to select whether this should
* set byte 0 (least significant), 1, 2, and so on up to 7 (most significant). {@code newValue} is a byte.
* @param value a double
* @param whichByte an int that will be used to select the byte to take from value (any int is allowed, only the bottom 3 bits are used to select)
* @param newValue a byte that will be placed into the returned double's bits at the selected position
* @return a double that results from changing the bits at the selected position to match newValue
*/
public static double setSelectedByte(final double value, final int whichByte, final byte newValue)
{
return Double.longBitsToDouble((Double.doubleToLongBits(value) & ~(255 << ((whichByte & 7) << 3)))
| ((newValue & 255) << ((whichByte & 7) << 3)));
}
/**
* Very limited-use; takes any double and produces a double in the -1.0 to 1.0 range, with similar inputs producing
* close to a consistent rate of up and down through the range. This is meant for noise, where it may be useful to
* limit the amount of change between nearby points' noise values and prevent sudden "jumps" in noise value.
* @param value any double
* @return a double from -1.0 (inclusive) to 1.0 (exclusive)
*/
public static double bounce(final double value)
{
final long s = Double.doubleToLongBits(value);
return Double.longBitsToDouble(((s ^ -((s & 0x8000000000000L)>>51)) & 0xfffffffffffffL)
| 0x4010000000000000L) - 5.0;
}
/**
* Very limited-use; takes any double and produces a double in the -1.0 to 1.0 range, with similar inputs producing
* close to a consistent rate of up and down through the range. This is meant for noise, where it may be useful to
* limit the amount of change between nearby points' noise values and prevent sudden "jumps" in noise value.
* @param value any double
* @return a double from -1.0 (inclusive) to 1.0 (exclusive)
*/
public static float bounce(final float value)
{
final int s = Float.floatToIntBits(value);
return Float.intBitsToFloat(((s ^ -((s & 0x00400000)>>22)) & 0x007fffff)
| 0x40800000) - 5f;
}
/**
* Very limited-use; takes the significand bits of a double, represented as a long of which this uses 52 bits, and
* produces a double in the -1.0 to 1.0 range, with similar inputs producing close to a consistent rate of up and
* down through the range. This is meant for noise, where it may be useful to limit the amount of change between
* nearby points' noise values and prevent sudden "jumps" in noise value.
* @param value any long; only the lower 52 bits will be used
* @return a double from -1.0 (inclusive) to 1.0 (exclusive)
*/
public static double bounce(final long value)
{
return Double.longBitsToDouble(((value ^ -((value & 0x8000000000000L)>>51)) & 0xfffffffffffffL)
| 0x4010000000000000L) - 5.0;
}
/**
* Very limited-use; takes the significand bits of a double, represented as a pair of ints {@code valueLow} and
* {@code valueHigh}, using all bits in valueLow and the least-significant 20 bits of valueHigh, and
* produces a double in the -1.0 to 1.0 range, with similar inputs producing close to a consistent rate of up and
* down through the range. This is meant for noise, where it may be useful to limit the amount of change between
* nearby points' noise values and prevent sudden "jumps" in noise value.
* @param valueLow any int; all bits will be used as the less-significant bits of the significand
* @param valueHigh any int; only the bottom 20 bits will be used as the more-significant bits of the significand
* @return a double from -1.0 (inclusive) to 1.0 (exclusive)
*/
public static double bounce(final int valueLow, final int valueHigh)
{
final long s = (((long) valueHigh) << 32 | valueLow);
return Double.longBitsToDouble(((s ^ -((s & 0x8000000000000L)>>51)) & 0xfffffffffffffL)
| 0x4010000000000000L) - 5.0;
}
/**
* Limited-use; takes any double and produces a double in the -1.0 to 1.0 range, with similar inputs producing
* close to a consistent rate of up and down through the range. This is meant for noise, where it may be useful to
* limit the amount of change between nearby points' noise values and prevent sudden "jumps" in noise value. It is
* very similar to {@link #bounce(double)}, but unlike bounce() this will maintain a continuous rate regardless of
* the magnitude of its input. An input of any even number should produce something very close to -1.0, any odd
* number should produce something very close to 1.0, and any number halfway between two incremental integers (like
* 8.5 or -10.5) should produce 0.0 or a very small fraction. This method is closely related to
* {@link #sway(double)}, which will smoothly curve its output to produce more values that are close to -1 or 1.
* @param value any double
* @return a double from -1.0 (inclusive) to 1.0 (inclusive)
*/
public static double zigzag(double value)
{
long floor = (value >= 0.0 ? (long) value : (long) value - 1L);
value -= floor;
floor = (-(floor & 1L) | 1L);
return value * (floor << 1) - floor;
}
/**
* Limited-use; takes any float and produces a float in the -1f to 1f range, with similar inputs producing
* close to a consistent rate of up and down through the range. This is meant for noise, where it may be useful to
* limit the amount of change between nearby points' noise values and prevent sudden "jumps" in noise value. It is
* very similar to {@link #bounce(float)}, but unlike bounce() this will maintain a continuous rate regardless of
* the magnitude of its input. An input of any even number should produce something very close to -1f, any odd
* number should produce something very close to 1f, and any number halfway between two incremental integers (like
* 8.5f or -10.5f) should produce 0f or a very small fraction. This method is closely related to
* {@link #sway(float)}, which will smoothly curve its output to produce more values that are close to -1 or 1.
* @param value any float
* @return a float from -1f (inclusive) to 1f (inclusive)
*/
public static float zigzag(float value)
{
int floor = (value >= 0f ? (int) value : (int) value - 1);
value -= floor;
floor = (-(floor & 1) | 1);
return value * (floor << 1) - floor;
}
/**
* Limited-use; takes any double and produces a double in the -1 to 1 range, with a graph of input to output that
* looks much like a sine wave, curving to have a flat slope when given an integer input and a steep slope when the
* input is halfway between two integers, smoothly curving at any points between those extremes. This is meant for
* noise, where it may be useful to limit the amount of change between nearby points' noise values and prevent both
* sudden "jumps" in noise value and "cracks" where a line takes a sudden jagged movement at an angle. It is very
* similar to {@link #bounce(double)} and {@link #zigzag(double)}, but unlike bounce() this will maintain its
* frequency of returning max or min values, regardless of the magnitude of its input (as long as there is enough
* floating-point precision to represent changes smaller than 1.0), and unlike zigzag() this will smooth its path.
* An input of any even number should produce something very close to -1.0, any odd number should produce something
* very close to 1.0, and any number halfway between two incremental integers (like 8.5 or -10.5) should produce 0.0
* or a very small fraction. In the (unlikely) event that this is given a double that is too large to represent
* many or any non-integer values, this will simply return -1.0 or 1.0.
* @param value any double other than NaN or infinite values; extremely large values can't work properly
* @return a double from -1.0 (inclusive) to 1.0 (inclusive)
*/
public static double sway(double value)
{
long floor = (value >= 0.0 ? (long) value : (long) value - 1L);
value -= floor;
floor = (-(floor & 1L) | 1L);
return value * value * value * (value * (value * 6.0 - 15.0) + 10.0) * (floor << 1) - floor;
}
/**
* Limited-use; takes any float and produces a float in the -1f to 1f range, with a graph of input to output that
* looks much like a sine wave, curving to have a flat slope when given an integer input and a steep slope when the
* input is halfway between two integers, smoothly curving at any points between those extremes. This is meant for
* noise, where it may be useful to limit the amount of change between nearby points' noise values and prevent both
* sudden "jumps" in noise value and "cracks" where a line takes a sudden jagged movement at an angle. It is very
* similar to {@link #bounce(float)} and {@link #zigzag(float)}, but unlike bounce() this will maintain its
* frequency of returning max or min values, regardless of the magnitude of its input (as long as there is enough
* floating-point precision to represent changes smaller than 1f), and unlike zigzag() this will smooth its path.
* An input of any even number should produce something very close to -1f, any odd number should produce something
* very close to 1f, and any number halfway between two incremental integers (like 8.5f or -10.5f) should produce 0f
* or a very small fraction. In the (unlikely) event that this is given a float that is too large to represent
* many or any non-integer values, this will simply return -1f or 1f.
* @param value any float other than NaN or infinite values; extremely large values can't work properly
* @return a float from -1f (inclusive) to 1f (inclusive)
*/
public static float sway(float value)
{
int floor = (value >= 0f ? (int) value : (int) value - 1);
value -= floor;
floor = (-(floor & 1) | 1);
return value * value * value * (value * (value * 6f - 15f) + 10f) * (floor << 1) - floor;
}
/**
* Limited-use; takes any float and produces a float in the 0f to 1f range, with a graph of input to output that
* looks much like a sine wave, curving to have a flat slope when given an integer input and a steep slope when the
* input is halfway between two integers, smoothly curving at any points between those extremes. This is meant for
* noise, where it may be useful to limit the amount of change between nearby points' noise values and prevent both
* sudden "jumps" in noise value and "cracks" where a line takes a sudden jagged movement at an angle. It is very
* similar to {@link #bounce(float)} and {@link #zigzag(float)}, but unlike bounce() this will not change its
* frequency of returning max or min values, regardless of the magnitude of its input (as long as there is enough
* floating-point precision to represent changes smaller than 1f), and unlike zigzag() this will smooth its path.
* An input of any even number should produce something very close to 0f, any odd number should produce something
* very close to 1f, and any number halfway between two incremental integers (like 8.5f or -10.5f) should produce
* 0.5f. In the (unlikely) event that this is given a float that is too large to represent many or any non-integer
* values, this will simply return 0f or 1f. This version is called "Tight" because its range is tighter than
* {@link #sway(float)}.
* @param value any float other than NaN or infinite values; extremely large values can't work properly
* @return a float from 0f (inclusive) to 1f (inclusive)
*/
public static float swayTight(float value)
{
int floor = (value >= 0f ? (int) value : (int) value - 1);
value -= floor;
floor &= 1;
return value * value * value * (value * (value * 6f - 15f) + 10f) * (-floor | 1) + floor;
}
/**
* Limited-use; takes any double and produces a double in the 0.0 to 1.0 range, with a graph of input to output that
* looks much like a sine wave, curving to have a flat slope when given an integer input and a steep slope when the
* input is halfway between two integers, smoothly curving at any points between those extremes. This is meant for
* noise, where it may be useful to limit the amount of change between nearby points' noise values and prevent both
* sudden "jumps" in noise value and "cracks" where a line takes a sudden jagged movement at an angle. It is very
* similar to {@link #bounce(double)} and {@link #zigzag(double)}, but unlike bounce() this will not change its
* frequency of returning max or min values, regardless of the magnitude of its input (as long as there is enough
* floating-point precision to represent changes smaller than 1.0), and unlike zigzag() this will smooth its path.
* An input of any even number should produce something very close to 0.0, any odd number should produce something
* very close to 1.0, and any number halfway between two incremental integers (like 8.5 or -10.5) should produce
* 0.5f. In the (unlikely) event that this is given a double that is too large to represent many or any non-integer
* values, this will simply return 0.0 or 1.0. This version is called "Tight" because its range is tighter than
* {@link #sway(double)}.
* @param value any double other than NaN or infinite values; extremely large values can't work properly
* @return a double from 0.0 (inclusive) to 1.0 (inclusive)
*/
public static double swayTight(double value)
{
long floor = (value >= 0.0 ? (long) value : (long) value - 1L);
value -= floor;
floor &= 1L;
return value * value * value * (value * (value * 6.0 - 15.0) + 10.0) * (-floor | 1L) + floor;
}
/**
* A mix of the smooth transitions of {@link #sway(double)} with (seeded) random peaks and valleys between -1.0 and
* 1.0 (both exclusive). The pattern this will produces will be completely different if the seed changes, and it is
* suitable for 1D noise. Uses a simple method of cubic interpolation between random values, where a random value is
* used without modification when given an integer for {@code value}. Note that this uses a different type of
* interpolation than {@link #sway(double)}, which uses quintic (this causes swayRandomized() to produce more
* outputs in the mid-range and less at extremes; it is also slightly faster and simpler).
*
* Performance note: HotSpot seems to be much more able to optimize swayRandomized(long, float) than
* swayRandomized(long, double), with the float version almost twice as fast after JIT warms up. On GWT, the
* reverse should be expected because floats must be emulated there.
* @param seed a long seed that will determine the pattern of peaks and valleys this will generate as value changes; this should not change between calls
* @param value a double that typically changes slowly, by less than 1.0, with direction changes at integer inputs
* @return a pseudo-random double between -1.0 and 1.0 (both exclusive), smoothly changing with value
*/
public static double swayRandomized(long seed, double value)
{
final long floor = value >= 0.0 ? (long) value : (long) value - 1L; // the closest long that is less than value
// gets a random start and endpoint. there's a sequence of start and end values for each seed, and changing the
// seed changes the start and end values unpredictably (so use the same seed for one curving line).
final double start = (((seed += floor * 0x6C8E9CF570932BD5L) ^ (seed >>> 25)) * (seed | 0xA529L)) * 0x0.fffffffffffffbp-63,
end = (((seed += 0x6C8E9CF570932BD5L) ^ (seed >>> 25)) * (seed | 0xA529L)) * 0x0.fffffffffffffbp-63;
// gets the fractional part of value
value -= floor;
// cubic interpolation to smooth the curve
value *= value * (3.0 - 2.0 * value);
// interpolate between start and end based on how far we are between the start and end points of this section
return (1.0 - value) * start + value * end;
}
/**
* A mix of the smooth transitions of {@link #sway(float)} with (seeded) random peaks and valleys between -1f and
* 1f (both exclusive). The pattern this will produces will be completely different if the seed changes, and it is
* suitable for 1D noise. Uses a simple method of cubic interpolation between random values, where a random value is
* used without modification when given an integer for {@code value}. Note that this uses a different type of
* interpolation than {@link #sway(float)}, which uses quintic (this causes swayRandomized() to produce more
* outputs in the mid-range and less at extremes; it is also slightly faster and simpler).
*
* Performance note: HotSpot seems to be much more able to optimize swayRandomized(long, float) than
* swayRandomized(long, double), with the float version almost twice as fast after JIT warms up. On GWT, the
* reverse should be expected because floats must be emulated there.
* @param seed a long seed that will determine the pattern of peaks and valleys this will generate as value changes; this should not change between calls
* @param value a float that typically changes slowly, by less than 2.0, with direction changes at integer inputs
* @return a pseudo-random float between -1f and 1f (both exclusive), smoothly changing with value
*/
public static float swayRandomized(long seed, float value)
{
final long floor = value >= 0f ? (long) value : (long) value - 1L;
final float start = (((seed += floor * 0x6C8E9CF570932BD5L) ^ (seed >>> 25)) * (seed | 0xA529L)) * 0x0.ffffffp-63f,
end = (((seed += 0x6C8E9CF570932BD5L) ^ (seed >>> 25)) * (seed | 0xA529L)) * 0x0.ffffffp-63f;
value -= floor;
value *= value * (3f - 2f * value);
return (1f - value) * start + value * end;
}
/**
* A variant on {@link #swayRandomized(long, float)} that takes an int seed instead of a float, and is optimized for
* usage on GWT. Like the version with a long seed, this uses cubic interpolation between random peak or valley
* points; only the method of generating those random peaks and valleys has changed.
* @param seed an int seed that will determine the pattern of peaks and valleys this will generate as value changes; this should not change between calls
* @param value a float that typically changes slowly, by less than 2.0, with direction changes at integer inputs
* @return a pseudo-random float between -1f and 1f (both exclusive), smoothly changing with value
*/
public static float swayRandomized(final int seed, float value)
{
final int floor = value >= 0f ? (int) value : (int) value - 1;
int z = seed + floor;
final float start = (((z = (z ^ 0xD1B54A35) * 0x102473) ^ (z << 11 | z >>> 21) ^ (z << 21 | z >>> 11)) * ((z ^ z >>> 15) | 0xFFE00001) + z) * 0x0.ffffffp-31f,
end = (((z = (seed + floor + 1 ^ 0xD1B54A35) * 0x102473) ^ (z << 11 | z >>> 21) ^ (z << 21 | z >>> 11)) * ((z ^ z >>> 15) | 0xFFE00001) + z) * 0x0.ffffffp-31f;
value -= floor;
value *= value * (3 - 2 * value);
return (1 - value) * start + value * end;
}
/**
* A 1D "noise" method that produces smooth transitions like {@link #sway(float)}, but also wrapping around at pi *
* 2 so this can be used to get smoothly-changing random angles. Has (seeded) random peaks and valleys where it
* slows its range of change, but can return any value from 0 to 6.283185307179586f, or pi * 2. The pattern this
* will produces will be completely different if the seed changes, and the value is expected to be something other
* than an angle, like time. Uses a simple method of cubic interpolation between random values, where a random value
* is used without modification when given an integer for {@code value}. Note that this uses a different type of
* interpolation than {@link #sway(float)}, which uses quintic (this causes swayAngleRandomized() to be slightly
* faster and simpler).
* @param seed a long seed that will determine the pattern of peaks and valleys this will generate as value changes; this should not change between calls
* @param value a float that typically changes slowly, by less than 1.0, with possible direction changes at integer inputs
* @return a pseudo-random float between 0f and 283185307179586f (both inclusive), smoothly changing with value and wrapping
*/
public static float swayAngleRandomized(long seed, float value)
{
final long floor = value >= 0f ? (long) value : (long) value - 1L;
float start = (((seed += floor * 0x6C8E9CF570932BD5L) ^ (seed >>> 25)) * (seed | 0xA529L) >>> 1) * 0x0.ffffffp-62f,
end = (((seed += 0x6C8E9CF570932BD5L) ^ (seed >>> 25)) * (seed | 0xA529L) >>> 1) * 0x0.ffffffp-62f;
value -= floor;
value *= value * (3f - 2f * value);
end = end - start + 1.5f;
end -= (long)end + 0.5f;
start += end * value + 1;
return (start - (long)start) * 6.283185307179586f;
}
/**
* Identical to {@link Float#floatToIntBits(float)} on desktop; optimized on GWT. Uses JS typed arrays on GWT, which
* are well-supported now across all recent browsers and have fallbacks in GWT in the unlikely event of a browser
* not supporting them.
* @param value a floating-point number.
* @return the bits that represent the floating-point number.
*/
public static int floatToIntBits(final float value)
{
return Float.floatToIntBits(value);
}
/**
* Identical to {@link Float#floatToIntBits(float)} on desktop (note, not {@link Float#floatToRawIntBits(float)});
* optimized on GWT. When compiling to JS via GWT, there is no way to distinguish NaN values with different bits but
* that are still NaN, so this doesn't try to somehow permit that. Uses JS typed arrays on GWT, which are
* well-supported now across all recent browsers and have fallbacks in GWT in the unlikely event of a browser not
* supporting them.
* @param value a floating-point number.
* @return the bits that represent the floating-point number.
*/
public static int floatToRawIntBits(final float value)
{
return Float.floatToIntBits(value);
}
/**
* Gets the bit representation of the given float {@code value}, but with reversed byte order. On desktop, this is
* equivalent to calling {@code Integer.reverseBytes(Float.floatToIntBits(value))}, but it is implemented using
* typed arrays on GWT.
* @param value a floating-point number
* @return the bits that represent the floating-point number, with their byte order reversed from normal.
*/
public static int floatToReversedIntBits(final float value) {
return Integer.reverseBytes(Float.floatToIntBits(value));
}
/**
* Reverses the byte order of {@code bits} and converts that to a float. On desktop, this is
* equivalent to calling {@code Float.intBitsToFloat(Integer.reverseBytes(bits))}, but it is implemented using
* typed arrays on GWT.
* @param bits an integer
* @return the {@code float} floating-point value with the given bits using their byte order reversed from normal.
*/
public static float reversedIntBitsToFloat(final int bits) {
return Float.intBitsToFloat(Integer.reverseBytes(bits));
}
/**
* Identical to {@link Float#intBitsToFloat(int)} on desktop; optimized on GWT. Uses JS typed arrays on GWT, which
* are well-supported now across all recent browsers and have fallbacks in GWT in the unlikely event of a browser
* not supporting them.
* @param bits an integer.
* @return the {@code float} floating-point value with the same bit pattern.
*/
public static float intBitsToFloat(final int bits)
{
return Float.intBitsToFloat(bits);
}
/**
* Gets an 8-bit section of the given float {@code value}, using {@code whichByte} to select whether this should
* return byte 0 (least significant), 1, 2, or 3 (most significant).
* @param value a float
* @param whichByte an int that will be used to select the byte to take from value (any int is allowed, only the bottom 2 bits are used to select)
* @return the selected byte from the given float
*/
public static byte getSelectedByte(final float value, final int whichByte)
{
return (byte)(Float.floatToIntBits(value) >>> ((whichByte & 3) << 3));
}
/**
* Like {@link #getSelectedByte(float, int)}, this sets the byte at a selected position in the int representation of
* a float, then returns the float produced by the bit change. Uses {@code whichByte} to select whether this should
* set byte 0 (least significant), 1, 2, or 3 (most significant). {@code newValue} is a byte.
* @param value a float
* @param whichByte an int that will be used to select the byte to take from value (any int is allowed, only the bottom 2 bits are used to select)
* @param newValue a byte that will be placed into the returned float's bits at the selected position
* @return a float that results from changing the bits at the selected position to match newValue
*/
public static float setSelectedByte(final float value, final int whichByte, final byte newValue)
{
return Float.intBitsToFloat((Float.floatToIntBits(value) & ~(255 << ((whichByte & 3) << 3)))
| ((newValue & 255) << ((whichByte & 3) << 3)));
}
/**
* Generates a pseudo-random double between 0.0 (inclusive) and 1.0 (exclusive) using the given long seed, passing
* it once through the (decent-quality and very fast) {@link ThrustAltRNG} algorithm.
*
* Consider calling this with {@code NumberTools.randomDouble(++seed)} for an optimal period of 2 to the 64 when
* repeatedly called, but {@code NumberTools.randomDouble(seed += ODD_LONG)} will also work just fine if ODD_LONG is
* any odd-number long, positive or negative.
* @param seed any long to be used as a seed
* @return a pseudo-random double from 0.0 (inclusive) to 1.0 (exclusive)
*/
public static double randomDouble(long seed)
{
return (((seed = ((seed *= 0x6C8E9CF570932BD5L) ^ (seed >>> 25)) * (seed | 0xA529L)) ^ (seed >>> 23)) & 0x1FFFFFFFFFFFFFL) * 0x1p-53;
}
/**
* Generates a pseudo-random double between -1.0 (inclusive) and 1.0 (exclusive) using the given long seed, passing
* it once through the (decent-quality and very fast) {@link ThrustAltRNG} algorithm.
*
* Consider calling this with {@code NumberTools.randomSignedDouble(++seed)} for an optimal period of 2 to the 64
* when repeatedly called, but {@code NumberTools.randomSignedDouble(seed += ODD_LONG)} will also work just fine if
* ODD_LONG is any odd-number long, positive or negative.
* @param seed any long to be used as a seed
* @return a pseudo-random double from 0.0 (inclusive) to 1.0 (exclusive)
*/
public static double randomSignedDouble(long seed)
{
return (((seed = ((seed *= 0x6C8E9CF570932BD5L) ^ (seed >>> 25)) * (seed | 0xA529L)) ^ (seed >>> 23)) >> 10) * 0x1p-53;
}
/**
* Generates a pseudo-random float between 0f (inclusive) and 1f (exclusive) using the given long seed, passing it
* once through the (decent-quality and very fast) {@link ThrustAltRNG} algorithm.
*
* Consider calling this with {@code NumberTools.randomFloat(++seed)} for an optimal period of 2 to the 64 when
* repeatedly called, but {@code NumberTools.randomFloat(seed += ODD_LONG)} will also work just fine if ODD_LONG is
* any odd-number long, positive or negative.
* @param seed any long to be used as a seed
* @return a pseudo-random float from -1.0f (exclusive) to 1.0f (exclusive)
*/
public static float randomFloat(long seed)
{
return (((seed = ((seed *= 0x6C8E9CF570932BD5L) ^ (seed >>> 25)) * (seed | 0xA529L)) ^ (seed >>> 23)) & 0xFFFFFF) * 0x1p-24f;
}
/**
* Generates a pseudo-random float between -1f (inclusive) and 1f (exclusive) using the given long seed, passing
* it once through the (decent-quality and very fast) {@link ThrustAltRNG} algorithm. This can be useful as a
* multiplier that has approximately equal likelihood of changing or leaving the sign of its multiplicand, and won't
* make the result larger (more significant) but will usually make it closer to 0.
*
* Consider calling this with {@code NumberTools.randomDouble(++seed)} for an optimal period of 2 to the 64 when
* repeatedly called, but {@code NumberTools.randomDouble(seed += ODD_LONG)} will also work just fine if ODD_LONG is
* any odd-number long, positive or negative.
* @param seed any long to be used as a seed
* @return a pseudo-random float from -1.0f (exclusive) to 1.0f (exclusive)
*/
public static float randomSignedFloat(long seed)
{
return (((seed = ((seed *= 0x6C8E9CF570932BD5L) ^ (seed >>> 25)) * (seed | 0xA529L)) ^ (seed >>> 23)) >> 39) * 0x1p-24f;
}
/**
* Generates a pseudo-random double between -1.0 (exclusive) and 1.0 (exclusive) with a distribution that has a
* strong central bias (around 0.0). Uses the given long seed, passing it once through the (decent-quality and very
* fast) {@link ThrustAltRNG} algorithm. This produces a pseudo-random long, which this simply passes to
* {@link #formCurvedFloat(long)}, since it is already well-suited to generating a curved distribution.
*
* Consider calling this with {@code NumberTools.randomFloatCurved(++seed)} for an optimal period of 2 to the 64
* when repeatedly called, but {@code NumberTools.randomFloatCurved(seed += ODD_LONG)} will also work just fine if
* ODD_LONG is any odd-number long, positive or negative.
* @param seed any int to be used as a seed
* @return a pseudo-random double from -1.0 (exclusive) to 1.0 (exclusive), distributed on a curve centered on 0.0
*/
public static float randomFloatCurved(long seed)
{
return formCurvedFloat(((seed = ((seed *= 0x6C8E9CF570932BD5L) ^ (seed >>> 25)) * (seed | 0xA529L)) ^ (seed >>> 23)));
}
/**
* Given an int as a seed, this uses its least-significant 23 bits to produce a float between 0f (inclusive) and 1f
* (exclusive). This does not randomize the seed at all, and the upper 9 bits of the seed are ignored.
* @param seed an int; only the bottom 23 bits will be used
* @return a float between 0f (inclusive) and 1f (exclusive)
*/
public static float formFloat(final int seed)
{
return Float.intBitsToFloat((seed & 0x7FFFFF) | 0x3f800000) - 1f;
}
/**
* Given an int as a seed, this uses its least-significant 23 bits to produce a float between -1f (inclusive) and 1f
* (exclusive). This does not randomize the seed at all, and the upper 9 bits of the seed are ignored.
* @param seed an int; only the bottom 23 bits will be used
* @return a float between -1f (inclusive) and 1f (exclusive)
*/
public static float formSignedFloat(final int seed)
{
return Float.intBitsToFloat((seed & 0x7FFFFF) | 0x40000000) - 3f;
}
/**
* Given a long as a seed, this uses its least-significant 52 bits to produce a double between 0 (inclusive) and 1
* (exclusive). This does not randomize the seed at all, and the upper 12 bits of the seed are ignored.
* @param seed a long; only the bottom 52 bits will be used
* @return a double between 0 (inclusive) and 1 (exclusive)
*/
public static double formDouble(final long seed)
{
return Double.longBitsToDouble((seed & 0xfffffffffffffL) | 0x3ff0000000000000L) - 1f;
}
/**
* Given a long as a seed, this uses its least-significant 52 bits to produce a double between -1 (inclusive) and 1
* (exclusive). This does not randomize the seed at all, and the upper 12 bits of the seed are ignored.
* @param seed a long; only the bottom 52 bits will be used
* @return a double between -1 (inclusive) and 1 (exclusive)
*/
public static double formSignedDouble(final long seed)
{
return Double.longBitsToDouble((seed & 0xfffffffffffffL) | 0x4000000000000000L) - 3f;
}
/**
* A different kind of determine-like method that expects to be given a random long and produces a random double
* with a curved distribution that centers on 0 (where it has a bias) and can (rarely) approach -1f and 1f.
* The distribution for the values is similar to Irwin-Hall, and is frequently near 0 but not too-rarely near -1.0
* or 1.0. It cannot produce 1.0, -1.0, or any values further from 0 than those bounds.
* @param start a long, usually random, such as one produced by any RandomnessSource; all bits will be used
* @return a deterministic double between -1.0 (exclusive) and 1.0 (exclusive); very likely to be close to 0.0
*/
public static double formCurvedDouble(long start) {
return longBitsToDouble((start >>> 12) | 0x3fe0000000000000L)
+ longBitsToDouble(((start *= 0x2545F4914F6CDD1DL) >>> 12) | 0x3fe0000000000000L)
- longBitsToDouble(((start *= 0x2545F4914F6CDD1DL) >>> 12) | 0x3fe0000000000000L)
- longBitsToDouble(((start * 0x2545F4914F6CDD1DL) >>> 12) | 0x3fe0000000000000L)
;
}
/**
* A different kind of determine-like method that expects to be given a random long and produces a random double
* with a curved distribution that centers on 0 (where it has a bias) and can (rarely) approach 0.0 and 1.0.
* The distribution for the values is similar to Irwin-Hall, and is frequently near 0 but not too-rarely near 0.0 or
* 1.0. It cannot produce 0.0, 1.0, or any values further from 0.5 than those bounds.
* @param start a long, usually random, such as one produced by any RandomnessSource; all bits will be used
* @return a deterministic double between 0.0 (exclusive) and 1.0 (exclusive); very likely to be close to 0.5
*/
public static double formCurvedDoubleTight(long start) {
return 0.5
+ longBitsToDouble((start >>> 12) | 0x3fd0000000000000L)
+ longBitsToDouble(((start *= 0x2545F4914F6CDD1DL) >>> 12) | 0x3fd0000000000000L)
- longBitsToDouble(((start *= 0x2545F4914F6CDD1DL) >>> 12) | 0x3fd0000000000000L)
- longBitsToDouble(((start * 0x2545F4914F6CDD1DL) >>> 12) | 0x3fd0000000000000L);
}
/**
* A different kind of determine-like method that expects to be given a random long and produces a random float with
* a curved distribution that centers on 0 (where it has a bias) and can (rarely) approach -1f and 1f.
* The distribution for the values is similar to Irwin-Hall, and is frequently near 0 but not too-rarely near -1f or
* 1f. It cannot produce 1f, -1f, or any values further from 0 than those bounds.
* @param start a long, usually random, such as one produced by any RandomnessSource
* @return a deterministic float between -1f (exclusive) and 1f (exclusive), that is very likely to be close to 0f
*/
public static float formCurvedFloat(final long start) {
return intBitsToFloat((int)start >>> 9 | 0x3F000000)
+ intBitsToFloat((int) (start >>> 41) | 0x3F000000)
- intBitsToFloat(((int)(start ^ ~start >>> 20) & 0x007FFFFF) | 0x3F000000)
- intBitsToFloat(((int) (~start ^ start >>> 30) & 0x007FFFFF) | 0x3F000000)
;
}
/**
* A different kind of determine-like method that expects to be given random ints and produces a random float with
* a curved distribution that centers on 0 (where it has a bias) and can (rarely) approach -1f and 1f.
* The distribution for the values is similar to Irwin-Hall, and is frequently near 0 but not too-rarely near -1f or
* 1f. It cannot produce 1f, -1f, or any values further from 0 than those bounds.
* @param start1 an int usually random, such as one produced by any RandomnessSource
* @param start2 an int usually random, such as one produced by any RandomnessSource
* @return a deterministic float between -1f (exclusive) and 1f (exclusive), that is very likely to be close to 0f
*/
public static float formCurvedFloat(final int start1, final int start2) {
return intBitsToFloat(start1 >>> 9 | 0x3F000000)
+ intBitsToFloat((~start1 & 0x007FFFFF) | 0x3F000000)
- intBitsToFloat(start2 >>> 9 | 0x3F000000)
- intBitsToFloat((~start2 & 0x007FFFFF) | 0x3F000000)
;
}
/**
* A different kind of determine-like method that expects to be given a random int and produces a random float with
* a curved distribution that centers on 0 (where it has a bias) and can (rarely) approach -1f and 1f.
* The distribution for the values is similar to Irwin-Hall, and is frequently near 0 but not too-rarely near -1f or
* 1f. It cannot produce 1f, -1f, or any values further from 0 than those bounds.
* @param start an int, usually random, such as one produced by any RandomnessSource
* @return a deterministic float between -1f (exclusive) and 1f (exclusive), that is very likely to be close to 0f
*/
public static float formCurvedFloat(final int start) {
return intBitsToFloat(start >>> 9 | 0x3F000000)
+ intBitsToFloat((start & 0x007FFFFF) | 0x3F000000)
- intBitsToFloat(((start << 18 & 0x007FFFFF) ^ ~start >>> 14) | 0x3F000000)
- intBitsToFloat(((start << 13 & 0x007FFFFF) ^ ~start >>> 19) | 0x3F000000)
;
}
/**
* Returns an int value with at most a single one-bit, in the position of the lowest-order ("rightmost") one-bit in
* the specified int value. Returns zero if the specified value has no one-bits in its two's complement binary
* representation, that is, if it is equal to zero.
*
* Identical to {@link Integer#lowestOneBit(int)}, but super-sourced to act correctly on GWT. If you have GWT as a
* target and do bit manipulation work, double-check everything! An int can be higher than {@link Integer#MAX_VALUE}
* or lower than {@link Integer#MIN_VALUE} on GWT, without actually being a long (internally it's a double). This
* is especially relevant for the overload of this method that takes and returns a long;
* {@link Long#lowestOneBit(long)} does not provide correct results for certain inputs on GWT, such as
* -17592186044416L, which it mysteriously returns 0L on, so you should use {@link #lowestOneBit(long)}.
* @param num the value whose lowest one bit is to be computed
* @return an int value with a single one-bit, in the position of the lowest-order one-bit in the specified value,
* or zero if the specified value is itself equal to zero.
*/
public static int lowestOneBit(int num)
{
return num & -num;
}
/**
* Returns an long value with at most a single one-bit, in the position of the lowest-order ("rightmost") one-bit in
* the specified long value. Returns zero if the specified value has no one-bits in its two's complement binary
* representation, that is, if it is equal to zero.
*
* Identical to {@link Long#lowestOneBit(long)}, but super-sourced to act correctly on GWT. If you have GWT as a
* target and do bit manipulation work, double-check everything! An int can be higher than {@link Integer#MAX_VALUE}
* or lower than {@link Integer#MIN_VALUE} on GWT, without actually being a long (internally it's a double). This
* is especially relevant for this overload (for longs more so than for ints); {@link Long#lowestOneBit(long)} does
* not provide correct results for certain inputs on GWT, such as -17592186044416L, which it mysteriously returns 0L
* on, so you should use this method.
* @param num the value whose lowest one bit is to be computed
* @return a long value with a single one-bit, in the position of the lowest-order one-bit in the specified value,
* or zero if the specified value is itself equal to zero.
*/
public static long lowestOneBit(long num)
{
return num & -num;
}
/**
* A fairly-close approximation of {@link Math#sin(double)} that can be significantly faster (between 8x and 80x
* faster sin() calls in benchmarking; if you have access to libGDX you should consider its sometimes-more-precise
* and sometimes-faster MathUtils.sin() method. Because this method doesn't rely on a
* lookup table, where libGDX's MathUtils does, applications that have a bottleneck on memory may perform better
* with this method than with MathUtils. Takes the same arguments Math.sin() does, so one angle in radians,
* which may technically be any double (but this will lose precision on fairly large doubles, such as those that are
* larger than {@link Long#MAX_VALUE}, because those doubles themselves will lose precision at that scale). This
* is closely related to {@link #sway(double)}, but the shape of the output when graphed is almost identical to
* sin(). The difference between the result of this method and {@link Math#sin(double)} should be under 0.0011 at
* all points between -pi and pi, with an average difference of about 0.0005; not all points have been checked for
* potentially higher errors, though.
*
* The error for this double version is extremely close to the float version, {@link #sin(float)}, so you should
* choose based on what type you have as input and/or want to return rather than on quality concerns. Coercion
* between float and double takes about as long as this method normally takes to run (or longer), so if you have
* floats you should usually use methods that take floats (or return floats, if assigning the result to a float),
* and likewise for doubles.
*
* Unlike in previous versions of this method, the sign of the input doesn't affect performance here, at least not
* by a measurable amount.
*
* The technique for sine approximation is mostly from
* this archived DevMaster thread,
* with credit to "Nick". Changes have been made to accelerate wrapping from any double to the valid input range.
* @param radians an angle in radians as a double, often from 0 to pi * 2, though not required to be.
* @return the sine of the given angle, as a double between -1.0 and 1.0 (both inclusive)
*/
public static double sin(double radians)
{
radians *= 0.6366197723675814;
final long floor = (radians >= 0.0 ? (long) radians : (long) radians - 1L) & -2L;
radians -= floor;
radians *= 2.0 - radians;
return radians * (-0.775 - 0.225 * radians) * ((floor & 2L) - 1L);
}
/**
* A fairly-close approximation of {@link Math#cos(double)} that can be significantly faster (between 8x and 80x
* faster cos() calls in benchmarking; if you have access to libGDX you should consider its sometimes-more-precise
* and sometimes-faster MathUtils.cos() method. Because this method doesn't rely on a
* lookup table, where libGDX's MathUtils does, applications that have a bottleneck on memory may perform better
* with this method than with MathUtils. Takes the same arguments Math.cos() does, so one angle in radians,
* which may technically be any double (but this will lose precision on fairly large doubles, such as those that are
* larger than {@link Long#MAX_VALUE}, because those doubles themselves will lose precision at that scale). This
* is closely related to {@link #sway(double)}, but the shape of the output when graphed is almost identical to
* cos(). The difference between the result of this method and {@link Math#cos(double)} should be under 0.0011 at
* all points between -pi and pi, with an average difference of about 0.0005; not all points have been checked for
* potentially higher errors, though.
*
* The error for this double version is extremely close to the float version, {@link #cos(float)}, so you should
* choose based on what type you have as input and/or want to return rather than on quality concerns. Coercion
* between float and double takes about as long as this method normally takes to run (or longer), so if you have
* floats you should usually use methods that take floats (or return floats, if assigning the result to a float),
* and likewise for doubles.
*
* Unlike in previous versions of this method, the sign of the input doesn't affect performance here, at least not
* by a measurable amount.
* The technique for cosine approximation is mostly from
* this archived DevMaster thread,
* with credit to "Nick". Changes have been made to accelerate wrapping from any double to the valid input range.
* @param radians an angle in radians as a double, often from 0 to pi * 2, though not required to be.
* @return the cosine of the given angle, as a double between -1.0 and 1.0 (both inclusive)
*/
public static double cos(double radians)
{
radians = radians * 0.6366197723675814 + 1.0;
final long floor = (radians >= 0.0 ? (long) radians : (long) radians - 1L) & -2L;
radians -= floor;
radians *= 2.0 - radians;
return radians * (-0.775 - 0.225 * radians) * ((floor & 2L) - 1L);
}
/**
* A fairly-close approximation of {@link Math#sin(double)} that can be significantly faster (between 8x and 80x
* faster sin() calls in benchmarking, and both takes and returns floats; if you have access to libGDX you should
* consider its more-precise and sometimes-faster MathUtils.sin() method. Because this method doesn't rely on a
* lookup table, where libGDX's MathUtils does, applications that have a bottleneck on memory may perform better
* with this method than with MathUtils. Takes the same arguments Math.sin() does, so one angle in radians,
* which may technically be any float (but this will lose precision on fairly large floats, such as those that are
* larger than {@link Integer#MAX_VALUE}, because those floats themselves will lose precision at that scale). This
* is closely related to {@link #sway(float)}, but the shape of the output when graphed is almost identical to
* sin(). The difference between the result of this method and {@link Math#sin(double)} should be under 0.0011 at
* all points between -pi and pi, with an average difference of about 0.0005; not all points have been checked for
* potentially higher errors, though.
*
* The error for this float version is extremely close to the double version, {@link #sin(double)}, so you should
* choose based on what type you have as input and/or want to return rather than on quality concerns. Coercion
* between float and double takes about as long as this method normally takes to run (or longer), so if you have
* floats you should usually use methods that take floats (or return floats, if assigning the result to a float),
* and likewise for doubles.
*
* Unlike in previous versions of this method, the sign of the input doesn't affect performance here, at least not
* by a measurable amount.
*
* The technique for sine approximation is mostly from
* this archived DevMaster thread,
* with credit to "Nick". Changes have been made to accelerate wrapping from any float to the valid input range.
* @param radians an angle in radians as a float, often from 0 to pi * 2, though not required to be.
* @return the sine of the given angle, as a float between -1f and 1f (both inclusive)
*/
public static float sin(float radians)
{
radians *= 0.6366197723675814f;
final int floor = (radians >= 0.0 ? (int) radians : (int) radians - 1) & -2;
radians -= floor;
radians *= 2f - radians;
return radians * (-0.775f - 0.225f * radians) * ((floor & 2) - 1);
}
/**
* A fairly-close approximation of {@link Math#cos(double)} that can be significantly faster (between 8x and 80x
* faster cos() calls in benchmarking, and both takes and returns floats; if you have access to libGDX you should
* consider its more-precise and sometimes-faster MathUtils.cos() method. Because this method doesn't rely on a
* lookup table, where libGDX's MathUtils does, applications that have a bottleneck on memory may perform better
* with this method than with MathUtils. Takes the same arguments Math.cos() does, so one angle in radians,
* which may technically be any float (but this will lose precision on fairly large floats, such as those that are
* larger than {@link Integer#MAX_VALUE}, because those floats themselves will lose precision at that scale). This
* is closely related to {@link #sway(float)}, but the shape of the output when graphed is almost identical to
* cos(). The difference between the result of this method and {@link Math#cos(double)} should be under 0.0011 at
* all points between -pi and pi, with an average difference of about 0.0005; not all points have been checked for
* potentially higher errors, though.
*
* The error for this float version is extremely close to the double version, {@link #cos(double)}, so you should
* choose based on what type you have as input and/or want to return rather than on quality concerns. Coercion
* between float and double takes about as long as this method normally takes to run (or longer), so if you have
* floats you should usually use methods that take floats (or return floats, if assigning the result to a float),
* and likewise for doubles.
*
* Unlike in previous versions of this method, the sign of the input doesn't affect performance here, at least not
* by a measurable amount.
*
* The technique for cosine approximation is mostly from
* this archived DevMaster thread,
* with credit to "Nick". Changes have been made to accelerate wrapping from any float to the valid input range.
* @param radians an angle in radians as a float, often from 0 to pi * 2, though not required to be.
* @return the cosine of the given angle, as a float between -1f and 1f (both inclusive)
*/
public static float cos(float radians)
{
radians = radians * 0.6366197723675814f + 1f;
final int floor = (radians >= 0.0 ? (int) radians : (int) radians - 1) & -2;
radians -= floor;
radians *= 2f - radians;
return radians * (-0.775f - 0.225f * radians) * ((floor & 2) - 1);
}
/**
* A fairly-close approximation of {@link Math#sin(double)} that can be significantly faster (between 8x and 80x
* faster sin() calls in benchmarking, and both takes and returns floats; if you have access to libGDX, you should
* consider its more-precise and sometimes-faster MathUtils.sinDeg() method. Because this method doesn't rely on a
* lookup table, where libGDX's MathUtils does, applications that have a bottleneck on memory may perform better
* with this method than with MathUtils. Takes one angle in degrees,
* which may technically be any float (but this will lose precision on fairly large floats, such as those that are
* larger than {@link Integer#MAX_VALUE}, because those floats themselves will lose precision at that scale). This
* is closely related to {@link #sway(float)}, but the shape of the output when graphed is almost identical to
* sin(). The difference between the result of this method and {@link Math#sin(double)} should be under 0.0011 at
* all points between -360 and 360, with an average difference of about 0.0005; not all points have been checked for
* potentially higher errors, though.
*
* The error for this float version is extremely close to the double version, {@link #sin(double)}, so you should
* choose based on what type you have as input and/or want to return rather than on quality concerns. Coercion
* between float and double takes about as long as this method normally takes to run (or longer), so if you have
* floats you should usually use methods that take floats (or return floats, if assigning the result to a float),
* and likewise for doubles.
*
* Unlike in previous versions of this method, the sign of the input doesn't affect performance here, at least not
* by a measurable amount.
*
* The technique for sine approximation is mostly from
* this archived DevMaster thread,
* with credit to "Nick". Changes have been made to accelerate wrapping from any float to the valid input range.
* @param degrees an angle in degrees as a float, often from 0 to 360, though not required to be.
* @return the sine of the given angle, as a float between -1f and 1f (both inclusive)
*/
public static float sinDegrees(float degrees)
{
degrees = degrees * 0.011111111111111112f;
final int floor = (degrees >= 0.0 ? (int) degrees : (int) degrees - 1) & -2;
degrees -= floor;
degrees *= 2f - degrees;
return degrees * (-0.775f - 0.225f * degrees) * ((floor & 2) - 1);
}
/**
* A fairly-close approximation of {@link Math#cos(double)} that can be significantly faster (between 8x and 80x
* faster cos() calls in benchmarking, and both takes and returns floats; if you have access to libGDX, you should
* consider its more-precise and sometimes-faster MathUtils.cosDeg() method. Because this method doesn't rely on a
* lookup table, where libGDX's MathUtils does, applications that have a bottleneck on memory may perform better
* with this method than with MathUtils. Takes one angle in degrees,
* which may technically be any float (but this will lose precision on fairly large floats, such as those that are
* larger than {@link Integer#MAX_VALUE}, because those floats themselves will lose precision at that scale). This
* is closely related to {@link #sway(float)}, but the shape of the output when graphed is almost identical to
* cos(). The difference between the result of this method and {@link Math#cos(double)} should be under 0.0011 at
* all points between -360 and 360, with an average difference of about 0.0005; not all points have been checked for
* potentially higher errors, though.
*
* The error for this float version is extremely close to the double version, {@link #cos(double)}, so you should
* choose based on what type you have as input and/or want to return rather than on quality concerns. Coercion
* between float and double takes about as long as this method normally takes to run (or longer), so if you have
* floats you should usually use methods that take floats (or return floats, if assigning the result to a float),
* and likewise for doubles.
*
* Unlike in previous versions of this method, the sign of the input doesn't affect performance here, at least not
* by a measurable amount.
*
* The technique for cosine approximation is mostly from
* this archived DevMaster thread,
* with credit to "Nick". Changes have been made to accelerate wrapping from any float to the valid input range.
* @param degrees an angle in degrees as a float, often from 0 to pi * 2, though not required to be.
* @return the cosine of the given angle, as a float between -1f and 1f (both inclusive)
*/
public static float cosDegrees(float degrees)
{
degrees = degrees * 0.011111111111111112f + 1f;
final int floor = (degrees >= 0.0 ? (int) degrees : (int) degrees - 1) & -2;
degrees -= floor;
degrees *= 2f - degrees;
return degrees * (-0.775f - 0.225f * degrees) * ((floor & 2) - 1);
}
/**
* A variation on {@link Math#sin(double)} that takes its input as a fraction of a turn instead of in radians; one
* turn is equal to 360 degrees or two*PI radians. This can be useful as a building block for other measurements;
* to make a sine method that takes its input in grad (with 400 grad equal to 360 degrees), you would just divide
* the grad value by 400.0 (or multiply it by 0.0025) and pass it to this method. Similarly for binary degrees, also
* called brad (with 256 brad equal to 360 degrees), you would divide by 256.0 or multiply by 0.00390625 before
* passing that value here. The brad case is especially useful because you can use a byte for any brad values, and
* adding up those brad values will wrap correctly (256 brad goes back to 0) while keeping perfect precision for the
* results (you still divide by 256.0 when you pass the brad value to this method).
*
* The error for this double version is extremely close to the float version, {@link #sin_(float)}, so you should
* choose based on what type you have as input and/or want to return rather than on quality concerns. Coercion
* between float and double takes about as long as this method normally takes to run (or longer), so if you have
* floats you should usually use methods that take floats (or return floats, if assigning the result to a float),
* and likewise for doubles.
*
* The technique for sine approximation is mostly from
* this archived DevMaster thread,
* with credit to "Nick". Changes have been made to accelerate wrapping from any double to the valid input range.
* @param turns an angle as a fraction of a turn as a double, with 0.5 here equivalent to PI radians in {@link #cos(double)}
* @return the sine of the given angle, as a double between -1.0 and 1.0 (both inclusive)
*/
public static double sin_(double turns)
{
turns *= 4.0;
final long floor = (turns >= 0.0 ? (long) turns : (long) turns - 1L) & -2L;
turns -= floor;
turns *= 2.0 - turns;
return turns * (-0.775 - 0.225 * turns) * ((floor & 2L) - 1L);
}
/**
* A variation on {@link Math#cos(double)} that takes its input as a fraction of a turn instead of in radians; one
* turn is equal to 360 degrees or two*PI radians. This can be useful as a building block for other measurements;
* to make a cosine method that takes its input in grad (with 400 grad equal to 360 degrees), you would just divide
* the grad value by 400.0 (or multiply it by 0.0025) and pass it to this method. Similarly for binary degrees, also
* called brad (with 256 brad equal to 360 degrees), you would divide by 256.0 or multiply by 0.00390625 before
* passing that value here. The brad case is especially useful because you can use a byte for any brad values, and
* adding up those brad values will wrap correctly (256 brad goes back to 0) while keeping perfect precision for the
* results (you still divide by 256.0 when you pass the brad value to this method).
*
* The error for this double version is extremely close to the float version, {@link #cos_(float)}, so you should
* choose based on what type you have as input and/or want to return rather than on quality concerns. Coercion
* between float and double takes about as long as this method normally takes to run (or longer), so if you have
* floats you should usually use methods that take floats (or return floats, if assigning the result to a float),
* and likewise for doubles.
*
* The technique for cosine approximation is mostly from
* this archived DevMaster thread,
* with credit to "Nick". Changes have been made to accelerate wrapping from any double to the valid input range.
* @param turns an angle as a fraction of a turn as a double, with 0.5 here equivalent to PI radians in {@link #cos(double)}
* @return the cosine of the given angle, as a double between -1.0 and 1.0 (both inclusive)
*/
public static double cos_(double turns)
{
turns = turns * 4.0 + 1.0;
final long floor = (turns >= 0.0 ? (long) turns : (long) turns - 1L) & -2L;
turns -= floor;
turns *= 2.0 - turns;
return turns * (-0.775 - 0.225 * turns) * ((floor & 2L) - 1L);
}
/**
* A variation on {@link Math#sin(double)} that takes its input as a fraction of a turn instead of in radians (it
* also takes and returns a float); one turn is equal to 360 degrees or two*PI radians. This can be useful as a
* building block for other measurements; to make a sine method that takes its input in grad (with 400 grad equal to
* 360 degrees), you would just divide the grad value by 400.0 (or multiply it by 0.0025) and pass it to this
* method. Similarly for binary degrees, also called brad (with 256 brad equal to 360 degrees), you would divide by
* 256.0 or multiply by 0.00390625 before passing that value here. The brad case is especially useful because you
* can use a byte for any brad values, and adding up those brad values will wrap correctly (256 brad goes back to 0)
* while keeping perfect precision for the results (you still divide by 256.0 when you pass the brad value to this
* method).
*
* The error for this float version is extremely close to the double version, {@link #sin_(double)}, so you should
* choose based on what type you have as input and/or want to return rather than on quality concerns. Coercion
* between float and double takes about as long as this method normally takes to run (or longer), so if you have
* floats you should usually use methods that take floats (or return floats, if assigning the result to a float),
* and likewise for doubles.
*
* The technique for sine approximation is mostly from
* this archived DevMaster thread,
* with credit to "Nick". Changes have been made to accelerate wrapping from any double to the valid input range.
* @param turns an angle as a fraction of a turn as a float, with 0.5 here equivalent to PI radians in {@link #cos(double)}
* @return the sine of the given angle, as a float between -1.0 and 1.0 (both inclusive)
*/
public static float sin_(float turns)
{
turns *= 4f;
final long floor = (turns >= 0.0 ? (long) turns : (long) turns - 1L) & -2L;
turns -= floor;
turns *= 2f - turns;
return turns * (-0.775f - 0.225f * turns) * ((floor & 2L) - 1L);
}
/**
* A variation on {@link Math#cos(double)} that takes its input as a fraction of a turn instead of in radians (it
* also takes and returns a float); one turn is equal to 360 degrees or two*PI radians. This can be useful as a
* building block for other measurements; to make a cosine method that takes its input in grad (with 400 grad equal
* to 360 degrees), you would just divide the grad value by 400.0 (or multiply it by 0.0025) and pass it to this
* method. Similarly for binary degrees, also called brad (with 256 brad equal to 360 degrees), you would divide by
* 256.0 or multiply by 0.00390625 before passing that value here. The brad case is especially useful because you
* can use a byte for any brad values, and adding up those brad values will wrap correctly (256 brad goes back to 0)
* while keeping perfect precision for the results (you still divide by 256.0 when you pass the brad value to this
* method).
*
* The error for this float version is extremely close to the float version, {@link #cos_(double)}, so you should
* choose based on what type you have as input and/or want to return rather than on quality concerns. Coercion
* between float and double takes about as long as this method normally takes to run (or longer), so if you have
* floats you should usually use methods that take floats (or return floats, if assigning the result to a float),
* and likewise for doubles.
*
* The technique for cosine approximation is mostly from
* this archived DevMaster thread,
* with credit to "Nick". Changes have been made to accelerate wrapping from any double to the valid input range.
* @param turns an angle as a fraction of a turn as a float, with 0.5 here equivalent to PI radians in {@link #cos(double)}
* @return the cosine of the given angle, as a float between -1.0 and 1.0 (both inclusive)
*/
public static float cos_(float turns)
{
turns = turns * 4f + 1f;
final long floor = (turns >= 0.0 ? (long) turns : (long) turns - 1L) & -2L;
turns -= floor;
turns *= 2f - turns;
return turns * (-0.775f - 0.225f * turns) * ((floor & 2L) - 1L);
}
/**
* Close approximation of the frequently-used trigonometric method atan2, with higher precision than LibGDX's atan2
* approximation. Maximum error is below 0.001 radians.
* Takes y and x (in that unusual order) as doubles, and returns the angle from the origin to that point in radians.
* It is about 5 times faster than {@link Math#atan2(double, double)} (roughly 17 ns instead of roughly 88 ns for
* Math, though the computer was under some load during testing). It is almost identical in speed to LibGDX'
* MathUtils approximation of the same method; MathUtils seems to have worse average error, though.
* Credit to StackExchange user njuffa, who gave
* this useful answer. This method changed from an earlier
* technique that was twice as fast but had very poor quality, enough to be visually noticeable. See also
* {@link #atan2Rough(double, double)} if the speed isn't good enough with this method and lower quality is OK, or
* {@link #atan2_(double, double)} if you don't want a mess converting to degrees or some other measurement, since
* that method returns an angle from 0.0 (equal to 0 degrees) to 1.0 (equal to 360 degrees).
* @param y y-component of the point to find the angle towards; note the parameter order is unusual by convention
* @param x x-component of the point to find the angle towards; note the parameter order is unusual by convention
* @return the angle to the given point, in radians as a double
*/
public static double atan2(final double y, final double x)
{
/*
a := min (|x|, |y|) / max (|x|, |y|)
s := a * a
r := ((-0.0464964749 * s + 0.15931422) * s - 0.327622764) * s * a + a
if |y| > |x| then r := 1.57079637 - r
if x < 0 then r := 3.14159274 - r
if y < 0 then r := -r
*/
if(y == 0.0 && x >= 0.0) return 0.0;
final double ax = Math.abs(x), ay = Math.abs(y);
if(ax < ay)
{
final double a = ax / ay, s = a * a,
r = 1.57079637 - (((-0.0464964749 * s + 0.15931422) * s - 0.327622764) * s * a + a);
return (x < 0.0) ? (y < 0.0) ? -3.14159274 + r : 3.14159274 - r : (y < 0.0) ? -r : r;
}
else {
final double a = ay / ax, s = a * a,
r = (((-0.0464964749 * s + 0.15931422) * s - 0.327622764) * s * a + a);
return (x < 0.0) ? (y < 0.0) ? -3.14159274 + r : 3.14159274 - r : (y < 0.0) ? -r : r;
}
}
/**
* Close approximation of the frequently-used trigonometric method atan2, with higher precision than LibGDX's atan2
* approximation. Maximum error is below 0.001 radians.
* Takes y and x (in that unusual order) as floats, and returns the angle from the origin to that point in radians.
* It is about 5 times faster than {@link Math#atan2(double, double)} (roughly 17 ns instead of roughly 88 ns for
* Math, though the computer was under some load during testing). It is almost identical in speed to LibGDX'
* MathUtils approximation of the same method; MathUtils seems to have worse average error, though.
* Credit to StackExchange user njuffa, who gave
* this useful answer. This method changed from an earlier
* technique that was twice as fast but had very poor quality, enough to be visually noticeable. See also
* {@link #atan2Rough(float, float)} if the speed isn't good enough with this method and lower quality is OK, or
* {@link #atan2_(float, float)} if you don't want a mess converting to degrees or some other measurement, since
* that method returns an angle from 0f (equal to 0 degrees) to 1f (equal to 360 degrees).
* @param y y-component of the point to find the angle towards; note the parameter order is unusual by convention
* @param x x-component of the point to find the angle towards; note the parameter order is unusual by convention
* @return the angle to the given point, in radians as a float
*/
public static float atan2(final float y, final float x)
{
/*
a := min (|x|, |y|) / max (|x|, |y|)
s := a * a
r := ((-0.0464964749 * s + 0.15931422) * s - 0.327622764) * s * a + a
if |y| > |x| then r := 1.57079637 - r
if x < 0 then r := 3.14159274 - r
if y < 0 then r := -r
*/
if(y == 0f && x >= 0f) return 0f;
final float ax = Math.abs(x), ay = Math.abs(y);
if(ax < ay)
{
final float a = ax / ay, s = a * a,
r = 1.57079637f - (((-0.0464964749f * s + 0.15931422f) * s - 0.327622764f) * s * a + a);
return (x < 0f) ? (y < 0f) ? -3.14159274f + r : 3.14159274f - r : (y < 0f) ? -r : r;
}
else {
final float a = ay / ax, s = a * a,
r = (((-0.0464964749f * s + 0.15931422f) * s - 0.327622764f) * s * a + a);
return (x < 0f) ? (y < 0f) ? -3.14159274f + r : 3.14159274f - r : (y < 0f) ? -r : r;
}
}
/**
* Less-precise but somewhat faster approximation of the frequently-used trigonometric method atan2, with
* worse average and max error than {@link #atan2(double, double)} but better error all-around than the old
* implementation of atan2() in SquidLib. Should be up to twice as fast as {@link #atan2(double, double)}.
* Should be fine for things at coarse-grid-level precision, like cells in a dungeon map, but less fitting for tasks
* like map projections that operate on finer grids.
*
* Credit to Sreeraman Rajan, Sichun Wang, Robert Inkol, and Alain Joyal in
* this DSP article.
* @param y y-component of the point to find the angle towards; note the parameter order is unusual by convention
* @param x x-component of the point to find the angle towards; note the parameter order is unusual by convention
* @return the angle to the given point, in radians as a double
*/
public static double atan2Rough(final double y, final double x)
{
if(y == 0f && x >= 0f) return 0.0;
final double ax = Math.abs(x), ay = Math.abs(y);
if(ax < ay)
{
final double a = ax / ay,
r = 1.57079637 - (a * (0.7853981633974483 + 0.273 * (1.0 - a)));
return (x < 0.0) ? (y < 0.0) ? -3.14159274 + r : 3.14159274 - r : (y < 0.0) ? -r : r;
}
else {
final double a = ay / ax,
r = (a * (0.7853981633974483 + 0.273 * (1.0 - a)));
return (x < 0.0) ? (y < 0.0) ? -3.14159274 + r : 3.14159274 - r : (y < 0.0) ? -r : r;
}
}
/**
* Less-precise but somewhat faster approximation of the frequently-used trigonometric method atan2, with
* worse average and max error than {@link #atan2(float, float)} but better error all-around than the old
* implementation of atan2() in SquidLib. Should be up to twice as fast as {@link #atan2(float, float)}.
* Should be fine for things at coarse-grid-level precision, like cells in a dungeon map, but less fitting for tasks
* like map projections that operate on finer grids.
*
* Credit to Sreeraman Rajan, Sichun Wang, Robert Inkol, and Alain Joyal in
* this DSP article.
* @param y y-component of the point to find the angle towards; note the parameter order is unusual by convention
* @param x x-component of the point to find the angle towards; note the parameter order is unusual by convention
* @return the angle to the given point, in radians as a float
*/
public static float atan2Rough(final float y, final float x)
{
if(y == 0f && x >= 0f) return 0f;
final float ax = Math.abs(x), ay = Math.abs(y);
if(ax < ay)
{
final float a = ax / ay,
r = 1.57079637f - (a * (0.7853981633974483f + 0.273f * (1f - a)));
return (x < 0f) ? (y < 0f) ? -3.14159274f + r : 3.14159274f - r : (y < 0f) ? -r : r;
}
else {
final float a = ay / ax,
r = (a * (0.7853981633974483f + 0.273f * (1f - a)));
return (x < 0f) ? (y < 0f) ? -3.14159274f + r : 3.14159274f - r : (y < 0f) ? -r : r;
}
}
/**
* Altered-range approximation of the frequently-used trigonometric method atan2, taking y and x positions as
* doubles and returning an angle measured in turns from 0.0 to 1.0 (inclusive), with one cycle over the range
* equivalent to 360 degrees or 2PI radians. You can multiply the angle by {@code 6.2831855f} to change to radians,
* or by {@code 360f} to change to degrees. Takes y and x (in that unusual order) as doubles. Will never return a
* negative number, which may help avoid costly floating-point modulus when you actually want a positive number.
* Credit to StackExchange user njuffa, who gave
* this useful answer. Note that
* {@link #atan2(double, double)} returns an angle in radians and can return negative results, which may be fine for
* many tasks; these two methods are extremely close in implementation and speed.
* @param y y-component of the point to find the angle towards; note the parameter order is unusual by convention
* @param x x-component of the point to find the angle towards; note the parameter order is unusual by convention
* @return the angle to the given point, as a double from 0.0 to 1.0, inclusive
*/
public static double atan2_(final double y, final double x)
{
if(y == 0.0 && x >= 0.0) return 0.0;
final double ax = Math.abs(x), ay = Math.abs(y);
if(ax < ay)
{
final double a = ax / ay, s = a * a,
r = 0.25 - (((-0.0464964749 * s + 0.15931422) * s - 0.327622764) * s * a + a) * 0.15915494309189535;
return (x < 0.0) ? (y < 0.0) ? 0.5 + r : 0.5 - r : (y < 0.0) ? 1.0 - r : r;
}
else {
final double a = ay / ax, s = a * a,
r = (((-0.0464964749 * s + 0.15931422) * s - 0.327622764) * s * a + a) * 0.15915494309189535;
return (x < 0.0) ? (y < 0.0) ? 0.5 + r : 0.5 - r : (y < 0.0) ? 1.0 - r : r;
}
}
/**
* Altered-range approximation of the frequently-used trigonometric method atan2, taking y and x positions as floats
* and returning an angle measured in turns from 0.0f to 1.0f, with one cycle over the range equivalent to 360
* degrees or 2PI radians. You can multiply the angle by {@code 6.2831855f} to change to radians, or by {@code 360f}
* to change to degrees. Takes y and x (in that unusual order) as floats. Will never return a negative number, which
* may help avoid costly floating-point modulus when you actually want a positive number.
* Credit to StackExchange user njuffa, who gave
* this useful answer. Note that
* {@link #atan2(float, float)} returns an angle in radians and can return negative results, which may be fine for
* many tasks; these two methods are extremely close in implementation and speed.
* @param y y-component of the point to find the angle towards; note the parameter order is unusual by convention
* @param x x-component of the point to find the angle towards; note the parameter order is unusual by convention
* @return the angle to the given point, as a float from 0.0f to 1.0f, inclusive
*/
public static float atan2_(final float y, final float x)
{
if(y == 0.0 && x >= 0.0) return 0f;
final float ax = Math.abs(x), ay = Math.abs(y);
if(ax < ay)
{
final float a = ax / ay, s = a * a,
r = 0.25f - (((-0.0464964749f * s + 0.15931422f) * s - 0.327622764f) * s * a + a) * 0.15915494309189535f;
return (x < 0.0f) ? (y < 0.0f) ? 0.5f + r : 0.5f - r : (y < 0.0f) ? 1f - r : r;
}
else {
final float a = ay / ax, s = a * a,
r = (((-0.0464964749f * s + 0.15931422f) * s - 0.327622764f) * s * a + a) * 0.15915494309189535f;
return (x < 0.0f) ? (y < 0.0f) ? 0.5f + r : 0.5f - r : (y < 0.0f) ? 1f - r : r;
}
}
/**
* Less-precise but somewhat faster altered-range approximation of the frequently-used trigonometric method atan2, with
* worse average and max error than {@link #atan2(double, double)} but better speed. Takes y and x positions as
* floats and returns an angle from 0.0f to 1.0f, with one cycle over the range equivalent to 360 degrees or 2PI
* radians. Should be up to twice as fast as {@link #atan2_(double, double)}.
* Should be fine for things at coarse-grid-level precision, like cells in a dungeon map, but less fitting for tasks
* like map projections that operate on finer grids.
*
* Credit to Sreeraman Rajan, Sichun Wang, Robert Inkol, and Alain Joyal in
* this DSP article.
* @param y y-component of the point to find the angle towards; note the parameter order is unusual by convention
* @param x x-component of the point to find the angle towards; note the parameter order is unusual by convention
* @return the angle to the given point, in radians as a double
*/
public static double atan2Rough_(final double y, final double x)
{
if(y == 0f && x >= 0f) return 0.0;
final double ax = Math.abs(x), ay = Math.abs(y);
if(ax < ay)
{
final double a = ax / ay,
r = 0.25 - (a * (0.7853981633974483 + 0.273 * (1.0 - a))) * 0.15915494309189535;
return (x < 0.0) ? (y < 0.0) ? 0.5 + r : 0.5 - r : (y < 0.0) ? 1.0 - r : r;
}
else {
final double a = ay / ax,
r = (a * (0.7853981633974483 + 0.273 * (1.0 - a))) * 0.15915494309189535;
return (x < 0.0) ? (y < 0.0) ? 0.5 + r : 0.5 - r : (y < 0.0) ? 1.0 - r : r;
}
}
/**
* Less-precise but somewhat faster approximation of the frequently-used trigonometric method atan2, with
* worse average and max error than {@link #atan2(float, float)} but better error all-around than the old
* implementation of atan2() in SquidLib. Should be up to twice as fast as {@link #atan2(float, float)}.
* Should be fine for things at coarse-grid-level precision, like cells in a dungeon map, but less fitting for tasks
* like map projections that operate on finer grids.
*
* Credit to Sreeraman Rajan, Sichun Wang, Robert Inkol, and Alain Joyal in
* this DSP article.
* @param y y-component of the point to find the angle towards; note the parameter order is unusual by convention
* @param x x-component of the point to find the angle towards; note the parameter order is unusual by convention
* @return the angle to the given point, in radians as a float
*/
public static float atan2Rough_(final float y, final float x)
{
if(y == 0f && x >= 0f) return 0f;
final float ax = Math.abs(x), ay = Math.abs(y);
if(ax < ay)
{
final float a = ax / ay,
r = 0.25f - (a * (0.7853981633974483f + 0.273f * (1f - a))) * 0.15915494309189535f;
return (x < 0f) ? (y < 0f) ? 0.5f + r : 0.5f - r : (y < 0f) ? 1f - r : r;
}
else {
final float a = ay / ax,
r = (a * (0.7853981633974483f + 0.273f * (1f - a))) * 0.15915494309189535f;
return (x < 0f) ? (y < 0f) ? 0.5f + r : 0.5f - r : (y < 0f) ? 1f - r : r;
}
}
/**
* Arc sine approximation with fairly low error while still being faster than {@link NumberTools#sin(double)}.
* This formula is number 201 in Dennis
* Kjaer Christensen's unfinished math work on arc sine approximation. This method is about 40 times faster
* than {@link Math#asin(double)}.
* @param a an input to the inverse sine function, from -1 to 1 inclusive (error is higher approaching -1 or 1)
* @return an output from the inverse sine function, from -PI/2 to PI/2 inclusive.
*/
public static double asin(double a) {
return (a * (1.0 + (a *= a) * (-0.141514171442891431 + a * -0.719110791477959357))) /
(1.0 + a * (-0.439110389941411144 + a * -0.471306172023844527));
}
/**
* Arc sine approximation with fairly low error while still being faster than {@link NumberTools#sin(float)}.
* This formula is number 201 in Dennis
* Kjaer Christensen's unfinished math work on arc sine approximation. This method is about 40 times faster
* than {@link Math#asin(double)}, and takes and returns a float.
* @param a an input to the inverse sine function, from -1 to 1 inclusive (error is higher approaching -1 or 1)
* @return an output from the inverse sine function, from -PI/2 to PI/2 inclusive.
*/
public static float asin(float a) {
return (a * (1f + (a *= a) * (-0.141514171442891431f + a * -0.719110791477959357f))) /
(1f + a * (-0.439110389941411144f + a * -0.471306172023844527f));
}
/**
* Arc cosine approximation with fairly low error while still being faster than {@link NumberTools#cos(double)}.
* This formula is number 201 in Dennis
* Kjaer Christensen's unfinished math work on arc sine approximation, with a basic change to go from arc sine
* to arc cosine. This method is faster than {@link Math#acos(double)}.
* @param a an input to the inverse cosine function, from -1 to 1 inclusive (error is higher approaching -1 or 1)
* @return an output from the inverse cosine function, from 0 to PI inclusive.
*/
public static double acos(double a) {
return 1.5707963267948966 - (a * (1.0 + (a *= a) * (-0.141514171442891431 + a * -0.719110791477959357))) /
(1.0 + a * (-0.439110389941411144 + a * -0.471306172023844527));
}
/**
* Arc cosine approximation with fairly low error while still being faster than {@link NumberTools#cos(float)}.
* This formula is number 201 in Dennis
* Kjaer Christensen's unfinished math work on arc sine approximation, with a basic change to go from arc sine
* to arc cosine. This method is faster than {@link Math#acos(double)}, and takes and returns a float.
* @param a an input to the inverse cosine function, from -1 to 1 inclusive (error is higher approaching -1 or 1)
* @return an output from the inverse cosine function, from 0 to PI inclusive.
*/
public static float acos(float a) {
return 1.5707963267948966f - (a * (1f + (a *= a) * (-0.141514171442891431f + a * -0.719110791477959357f))) /
(1f + a * (-0.439110389941411144f + a * -0.471306172023844527f));
}
/**
* Inverse sine function (arcsine) but with output measured in turns instead of radians. Possible results for this
* range from 0.75 (inclusive) to 1.0 (exclusive), and continuing past that to 0.0 (inclusive) to 0.25 (inclusive).
*
* This method is much more precise than the non-turn approximation, but is about 3x slower.
* @param n a double from -1.0 to 1.0 (both inclusive), usually the output of sin() or cos()
* @return one of the values that would produce {@code n} if it were passed to {@link #sin_(double)}
*/
public static double asin_(final double n)
{
if(n == 0.0) return 0.0;
final double ax = Math.sqrt(1.0 - n * n), ay = Math.abs(n);
if(ax < ay)
{
final double a = ax / ay, s = a * a,
r = 0.25 - (((-0.0464964749 * s + 0.15931422) * s - 0.327622764) * s * a + a) * 0.15915494309189535;
return (n < 0.0) ? 1.0 - r : r;
}
else {
final double a = ay / ax, s = a * a,
r = (((-0.0464964749 * s + 0.15931422) * s - 0.327622764) * s * a + a) * 0.15915494309189535;
return (n < 0.0) ? 1.0 - r : r;
}
}
/**
* Inverse cosine function (arccos) but with output measured in turns instead of radians. Possible results for this
* range from 0.0 (inclusive) to 0.5 (inclusive).
*
* This method is much more precise than the non-turn approximation, but is about 3x slower.
* @param n a double from -1.0 to 1.0 (both inclusive), usually the output of sin() or cos()
* @return one of the values that would produce {@code n} if it were passed to {@link #cos_(double)}
*/
public static double acos_(final double n)
{
if(n == 1.0 || n == -1.0) return 0.0;
final double ax = Math.abs(n), ay = Math.sqrt((1.0 + n) * (1.0 - n));
if(ax < ay)
{
final double a = ax / ay, s = a * a,
r = 0.25 - (((-0.0464964749 * s + 0.15931422) * s - 0.327622764) * s * a + a) * 0.15915494309189535;
return (n < 0.0) ? 0.5 - r : r;
}
else {
final double a = ax / ay, s = a * a,
r = 0.25 - (((-0.0464964749 * s + 0.15931422) * s - 0.327622764) * s * a + a) * 0.15915494309189535;
return (n < 0.0) ? 0.5 - r : r;
}
}
/**
* Inverse sine function (arcsine) but with output measured in turns instead of radians. Possible results for this
* range from 0.75f (inclusive) to 1.0f (exclusive), and continuing past that to 0.0f (inclusive) to 0.25f
* (inclusive).
*
* This method is much more precise than the non-turn approximation, but is about 3x slower.
* @param n a float from -1.0f to 1.0f (both inclusive), usually the output of sin() or cos()
* @return one of the values that would produce {@code n} if it were passed to {@link #sin_(float)}
*/
public static float asin_(final float n)
{
if(n == 0.0f) return 0.0f;
final float ax = (float) Math.sqrt(1f - n * n), ay = Math.abs(n);
if(ax < ay)
{
final float a = ax / ay, s = a * a,
r = 0.25f - (((-0.0464964749f * s + 0.15931422f) * s - 0.327622764f) * s * a + a) * 0.15915494309189535f;
return (n < 0.0f) ? 1.0f - r : r;
}
else {
final float a = ay / ax, s = a * a,
r = (((-0.0464964749f * s + 0.15931422f) * s - 0.327622764f) * s * a + a) * 0.15915494309189535f;
return (n < 0.0f) ? 1.0f - r : r;
}
}
/**
* Inverse cosine function (arccos) but with output measured in turns instead of radians. Possible results for this
* range from 0.0f (inclusive) to 0.5f (inclusive).
*
* This method is much more precise than the non-turn approximation, but is about 3x slower.
* @param n a float from -1.0f to 1.0f (both inclusive), usually the output of sin() or cos()
* @return one of the values that would produce {@code n} if it were passed to {@link #cos_(float)}
*/
public static float acos_(final float n)
{
if(n == 1.0f || n == -1.0f) return 0.0f;
final float ax = Math.abs(n), ay = (float) Math.sqrt((1f + n) * (1f - n));
if(ax < ay)
{
final float a = ax / ay, s = a * a,
r = 0.25f - (((-0.0464964749f * s + 0.15931422f) * s - 0.327622764f) * s * a + a) * 0.15915494309189535f;
return (n < 0.0f) ? 0.5f - r : r;
}
else {
final float a = ax / ay, s = a * a,
r = (((-0.0464964749f * s + 0.15931422f) * s - 0.327622764f) * s * a + a) * 0.15915494309189535f;
return (n < 0.0f) ? 0.5f - r : r;
}
}
}