Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

define machine epsilon constants #9

Merged
merged 1 commit into from
Aug 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 9 additions & 6 deletions src/main/java/com/github/tommyettinger/digital/Hasher.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
import static com.github.tommyettinger.digital.BitConversion.doubleToRawLongBits;
import static com.github.tommyettinger.digital.BitConversion.floatToRawIntBits;

import static com.github.tommyettinger.digital.MathTools.EPSILON;
import static com.github.tommyettinger.digital.MathTools.EPSILON_D;

/**
* 64-bit and 32-bit hashing functions that we can rely on staying the same cross-platform.
* This uses a family of algorithms all based on Wang Yi's wyhash, but using at most 64-bit
Expand Down Expand Up @@ -314,7 +317,7 @@ public static int randomize3Bounded(long state, int bound) {
* @return a pseudo-random float between 0f (inclusive) and 1f (exclusive), determined by {@code state}
*/
public static float randomize1Float(long state) {
return ((((state = (((state * 0x632BE59BD9B4E019L) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L)) ^ state >>> 27) * 0xAEF17502108EF2D9L) >>> 40) * 0x1p-24f;
return ((((state = (((state * 0x632BE59BD9B4E019L) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L)) ^ state >>> 27) * 0xAEF17502108EF2D9L) >>> 40) * EPSILON;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's interesting that the multiplier used to produce the most valid zero-to-one floats with uniform spacing is also the machine epsilon; I am guessing that this isn't a coincidence.

}

/**
Expand Down Expand Up @@ -345,7 +348,7 @@ public static float randomize1Float(long state) {
*/
public static float randomize2Float(long state) {
state ^= 0xD1B54A32D192ED03L;
return ((((state = (state ^ (state << 39 | state >>> 25) ^ (state << 17 | state >>> 47)) * 0x9E6C63D0676A9A99L) ^ state >>> 23 ^ state >>> 51) * 0x9E6D62D06F6A9A9BL) >>> 40) * 0x1p-24f;
return ((((state = (state ^ (state << 39 | state >>> 25) ^ (state << 17 | state >>> 47)) * 0x9E6C63D0676A9A99L) ^ state >>> 23 ^ state >>> 51) * 0x9E6D62D06F6A9A9BL) >>> 40) * EPSILON;
}

/**
Expand Down Expand Up @@ -382,7 +385,7 @@ public static float randomize3Float(long state) {
state *= 0xBEA225F9EB34556DL;
state ^= state >>> 32;
state *= 0xBEA225F9EB34556DL;
return (state >>> 40) * 0x1p-24f;
return (state >>> 40) * EPSILON;
}

/**
Expand Down Expand Up @@ -410,7 +413,7 @@ public static float randomize3Float(long state) {
* @return a pseudo-random double between 0.0 (inclusive) and 1.0 (exclusive), determined by {@code state}
*/
public static double randomize1Double(long state) {
return (((state = ((state = (((state * 0x632BE59BD9B4E019L) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L)) ^ state >>> 27) * 0xAEF17502108EF2D9L) ^ state >>> 25) & 0x1FFFFFFFFFFFFFL) * 0x1p-53;
return (((state = ((state = (((state * 0x632BE59BD9B4E019L) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L)) ^ state >>> 27) * 0xAEF17502108EF2D9L) ^ state >>> 25) & 0x1FFFFFFFFFFFFFL) * EPSILON_D;
}

/**
Expand Down Expand Up @@ -440,7 +443,7 @@ public static double randomize1Double(long state) {
*/
public static double randomize2Double(long state) {
state ^= 0xD1B54A32D192ED03L;
return (((state = ((state = (state ^ (state << 39 | state >>> 25) ^ (state << 17 | state >>> 47)) * 0x9E6C63D0676A9A99L) ^ state >>> 23 ^ state >>> 51) * 0x9E6D62D06F6A9A9BL) ^ state >>> 23) >>> 11) * 0x1p-53;
return (((state = ((state = (state ^ (state << 39 | state >>> 25) ^ (state << 17 | state >>> 47)) * 0x9E6C63D0676A9A99L) ^ state >>> 23 ^ state >>> 51) * 0x9E6D62D06F6A9A9BL) ^ state >>> 23) >>> 11) * EPSILON_D;
}

/**
Expand Down Expand Up @@ -476,7 +479,7 @@ public static double randomize3Double(long state) {
state *= 0xBEA225F9EB34556DL;
state ^= state >>> 32;
state *= 0xBEA225F9EB34556DL;
return (state >>> 11 ^ state >>> 40) * 0x1p-53;
return (state >>> 11 ^ state >>> 40) * EPSILON_D;
}

/**
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/com/github/tommyettinger/digital/MathTools.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,18 @@ private MathTools() {
* false-positive equivalence with very small inputs.
*/
public static final float FLOAT_ROUNDING_ERROR = 0x1p-20f; // was 0.000001f

/**
* The smallest measurable difference between a given {@code float} value and a directly adjacent value.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is right; the smallest measurable difference varies a lot based on the magnitude of the floats, and would be measured as one ulp. This is, however, the smallest non-zero distance possible between two floats returned by Random#nextFloat(), if my math is right.

* Useful for converting a 64-bit {@code long} value to a gradient between 0 and 1.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also a bit of a nit-pick here, this is useful for converting non-negative up-to-24-bit ints or longs to fit in a uniformly-spaced 0 to 1 range. It can work on more than just long, and it probably doesn't do what you want if you multiply an arbitrary (possibly negative) long by this.

*/
public static final float EPSILON = 0x1p-24f;

/**
* The smallest measurable difference between a given {@code double} value and a directly adjacent value.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also the comment about an ulp above applies here. This might be the smallest non-zero distance possible between two doubles returned by Random#nextDouble(), but Random specifically might not be so precise. All of the EnhancedRandom classes in juniper have a nextDouble() that matches this precision.

* Useful for converting a 64-bit {@code long} value to a gradient between 0 and 1.
*/
public static final double EPSILON_D = 0x1p-53;

/**
* The {@code float} value that is closer than any other to
Expand Down