mirror of https://github.com/apache/lucene.git
LUCENE-7168: use center value on decode
This commit is contained in:
parent
5e4777346a
commit
1848477bd8
|
@ -23,7 +23,7 @@ class Geo3DUtil {
|
|||
private static final double MAX_VALUE = PlanetModel.WGS84.getMaximumMagnitude();
|
||||
private static final int BITS = 32;
|
||||
private static final double MUL = (0x1L<<BITS)/(2*MAX_VALUE);
|
||||
static final double DECODE = getNextSafeDouble(1/MUL);
|
||||
static final double DECODE = 1/MUL;
|
||||
private static final int MIN_ENCODED_VALUE = encodeValue(-MAX_VALUE);
|
||||
|
||||
public static int encodeValue(double x) {
|
||||
|
@ -33,6 +33,10 @@ class Geo3DUtil {
|
|||
if (x < -MAX_VALUE) {
|
||||
throw new IllegalArgumentException("value=" + x + " is out-of-bounds (less than than WGS84's -planetMax=" + -MAX_VALUE + ")");
|
||||
}
|
||||
// the maximum possible value cannot be encoded without overflow
|
||||
if (x == MAX_VALUE) {
|
||||
x = Math.nextDown(x);
|
||||
}
|
||||
long result = (long) Math.floor(x / DECODE);
|
||||
//System.out.println(" enc: " + x + " -> " + result);
|
||||
assert result >= Integer.MIN_VALUE;
|
||||
|
@ -41,35 +45,8 @@ class Geo3DUtil {
|
|||
}
|
||||
|
||||
public static double decodeValue(int x) {
|
||||
double result;
|
||||
if (x == MIN_ENCODED_VALUE) {
|
||||
// We must special case this, because -MAX_VALUE is not guaranteed to land precisely at a floor value, and we don't ever want to
|
||||
// return a value outside of the planet's range (I think?). The max value is "safe" because we floor during encode:
|
||||
result = -MAX_VALUE;
|
||||
} else {
|
||||
result = x * DECODE;
|
||||
}
|
||||
assert result >= -MAX_VALUE && result <= MAX_VALUE;
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Returns a double value >= x such that if you multiply that value by an int, and then
|
||||
* divide it by that int again, you get precisely the same value back */
|
||||
private static double getNextSafeDouble(double x) {
|
||||
|
||||
// Move to double space:
|
||||
long bits = Double.doubleToLongBits(x);
|
||||
|
||||
// Make sure we are beyond the actual maximum value:
|
||||
bits += Integer.MAX_VALUE;
|
||||
|
||||
// Clear the bottom 32 bits:
|
||||
bits &= ~((long) Integer.MAX_VALUE);
|
||||
|
||||
// Convert back to double:
|
||||
double result = Double.longBitsToDouble(bits);
|
||||
assert result > x;
|
||||
return result;
|
||||
// We decode to the center value; this keeps the encoding stable
|
||||
return (x+0.5) * DECODE;
|
||||
}
|
||||
|
||||
/** Returns smallest double that would encode to int x. */
|
||||
|
@ -81,7 +58,10 @@ class Geo3DUtil {
|
|||
/** Returns largest double that would encode to int x. */
|
||||
// NOTE: keep this package private!!
|
||||
static double decodeValueCeil(int x) {
|
||||
assert x < Integer.MAX_VALUE;
|
||||
return Math.nextDown((x+1) * DECODE);
|
||||
if (x == Integer.MAX_VALUE) {
|
||||
return MAX_VALUE;
|
||||
} else {
|
||||
return Math.nextDown((x+1) * DECODE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -728,7 +728,7 @@ public class TestGeo3DPoint extends LuceneTestCase {
|
|||
|
||||
public void testToString() {
|
||||
Geo3DPoint point = new Geo3DPoint("point", 44.244272, 7.769736);
|
||||
assertEquals("Geo3DPoint <point: x=0.7094263127744131 y=0.09679758888428691 z=0.6973564619016113>", point.toString());
|
||||
assertEquals("Geo3DPoint <point: x=0.7094263130517758 y=0.09679758927665334 z=0.6973564618592686>", point.toString());
|
||||
}
|
||||
|
||||
public void testShapeQueryToString() {
|
||||
|
@ -1078,25 +1078,6 @@ public class TestGeo3DPoint extends LuceneTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
// Takes ~35 seconds on modern-ish 2015 dev box:
|
||||
@Nightly
|
||||
public void testEncodeIsStableFromIntSide() throws Exception {
|
||||
double max = PlanetModel.WGS84.getMaximumMagnitude();
|
||||
|
||||
// We can't test the full space of ints (Integer.MIN_VALUE to Integer.MAX_VALUE) because not all ints are allowed:
|
||||
int start = Geo3DUtil.encodeValue(-max);
|
||||
int end = Geo3DUtil.encodeValue(max);
|
||||
// This prints: 99.99997175764292
|
||||
//System.out.println("PCTG INT SPACE USED: " + 100.*(((long) end)-(long) start)/(1L<<32));
|
||||
for (int i=start;i<=end;i++) {
|
||||
double x = Geo3DUtil.decodeValue(i);
|
||||
assertEquals(i, Geo3DUtil.encodeValue(x));
|
||||
if (i > start+1) {
|
||||
assertEquals(Geo3DUtil.DECODE, x - Geo3DUtil.decodeValue(i-1), 0.0d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Clips the incoming value to the allowed min/max range before encoding, instead of throwing an exception. */
|
||||
private static int encodeValueLenient(double x) {
|
||||
double planetMax = PlanetModel.WGS84.getMaximumMagnitude();
|
||||
|
|
Loading…
Reference in New Issue