mirror of https://github.com/apache/lucene.git
LUCENE-7594: Fixed point range queries on floating-point types to recommend using helpers for exclusive bounds that are consistent with Double.compare.
This commit is contained in:
parent
5020ea28bc
commit
18d53a43f7
|
@ -109,6 +109,10 @@ Bug Fixes
|
||||||
there are too many merges running and one of the merges hits a
|
there are too many merges running and one of the merges hits a
|
||||||
tragic exception (Joey Echeverria via Mike McCandless)
|
tragic exception (Joey Echeverria via Mike McCandless)
|
||||||
|
|
||||||
|
* LUCENE-7594: Fixed point range queries on floating-point types to recommend
|
||||||
|
using helpers for exclusive bounds that are consistent with Double.compare.
|
||||||
|
(Adrien Grand, Dawid Weiss)
|
||||||
|
|
||||||
Improvements
|
Improvements
|
||||||
|
|
||||||
* LUCENE-6824: TermAutomatonQuery now rewrites to TermQuery,
|
* LUCENE-6824: TermAutomatonQuery now rewrites to TermQuery,
|
||||||
|
|
|
@ -45,6 +45,32 @@ import org.apache.lucene.util.NumericUtils;
|
||||||
*/
|
*/
|
||||||
public final class DoublePoint extends Field {
|
public final class DoublePoint extends Field {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the least double that compares greater than {@code d} consistently
|
||||||
|
* with {@link Double#compare}. The only difference with
|
||||||
|
* {@link Math#nextUp(double)} is that this method returns {@code +0d} when
|
||||||
|
* the argument is {@code -0d}.
|
||||||
|
*/
|
||||||
|
public static double nextUp(double d) {
|
||||||
|
if (Double.doubleToLongBits(d) == 0x8000_0000_0000_0000L) { // -0d
|
||||||
|
return +0d;
|
||||||
|
}
|
||||||
|
return Math.nextUp(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the greatest double that compares less than {@code d} consistently
|
||||||
|
* with {@link Double#compare}. The only difference with
|
||||||
|
* {@link Math#nextDown(double)} is that this method returns {@code -0d} when
|
||||||
|
* the argument is {@code +0d}.
|
||||||
|
*/
|
||||||
|
public static double nextDown(double d) {
|
||||||
|
if (Double.doubleToLongBits(d) == 0L) { // +0d
|
||||||
|
return -0f;
|
||||||
|
}
|
||||||
|
return Math.nextDown(d);
|
||||||
|
}
|
||||||
|
|
||||||
private static FieldType getType(int numDims) {
|
private static FieldType getType(int numDims) {
|
||||||
FieldType type = new FieldType();
|
FieldType type = new FieldType();
|
||||||
type.setDimensions(numDims, Double.BYTES);
|
type.setDimensions(numDims, Double.BYTES);
|
||||||
|
@ -164,8 +190,8 @@ public final class DoublePoint extends Field {
|
||||||
* <p>
|
* <p>
|
||||||
* You can have half-open ranges (which are in fact </≤ or >/≥ queries)
|
* You can have half-open ranges (which are in fact </≤ or >/≥ queries)
|
||||||
* by setting {@code lowerValue = Double.NEGATIVE_INFINITY} or {@code upperValue = Double.POSITIVE_INFINITY}.
|
* by setting {@code lowerValue = Double.NEGATIVE_INFINITY} or {@code upperValue = Double.POSITIVE_INFINITY}.
|
||||||
* <p> Ranges are inclusive. For exclusive ranges, pass {@code Math#nextUp(lowerValue)}
|
* <p> Ranges are inclusive. For exclusive ranges, pass {@link #nextUp(double) nextUp(lowerValue)}
|
||||||
* or {@code Math.nextDown(upperValue)}.
|
* or {@link #nextUp(double) nextDown(upperValue)}.
|
||||||
* <p>
|
* <p>
|
||||||
* Range comparisons are consistent with {@link Double#compareTo(Double)}.
|
* Range comparisons are consistent with {@link Double#compareTo(Double)}.
|
||||||
*
|
*
|
||||||
|
|
|
@ -45,6 +45,32 @@ import org.apache.lucene.util.NumericUtils;
|
||||||
*/
|
*/
|
||||||
public final class FloatPoint extends Field {
|
public final class FloatPoint extends Field {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the least float that compares greater than {@code f} consistently
|
||||||
|
* with {@link Float#compare}. The only difference with
|
||||||
|
* {@link Math#nextUp(float)} is that this method returns {@code +0f} when
|
||||||
|
* the argument is {@code -0f}.
|
||||||
|
*/
|
||||||
|
public static float nextUp(float f) {
|
||||||
|
if (Float.floatToIntBits(f) == 0x8000_0000) { // -0f
|
||||||
|
return +0f;
|
||||||
|
}
|
||||||
|
return Math.nextUp(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the greatest float that compares less than {@code f} consistently
|
||||||
|
* with {@link Float#compare}. The only difference with
|
||||||
|
* {@link Math#nextDown(float)} is that this method returns {@code -0f} when
|
||||||
|
* the argument is {@code +0f}.
|
||||||
|
*/
|
||||||
|
public static float nextDown(float f) {
|
||||||
|
if (Float.floatToIntBits(f) == 0) { // +0f
|
||||||
|
return -0f;
|
||||||
|
}
|
||||||
|
return Math.nextDown(f);
|
||||||
|
}
|
||||||
|
|
||||||
private static FieldType getType(int numDims) {
|
private static FieldType getType(int numDims) {
|
||||||
FieldType type = new FieldType();
|
FieldType type = new FieldType();
|
||||||
type.setDimensions(numDims, Float.BYTES);
|
type.setDimensions(numDims, Float.BYTES);
|
||||||
|
@ -164,8 +190,8 @@ public final class FloatPoint extends Field {
|
||||||
* <p>
|
* <p>
|
||||||
* You can have half-open ranges (which are in fact </≤ or >/≥ queries)
|
* You can have half-open ranges (which are in fact </≤ or >/≥ queries)
|
||||||
* by setting {@code lowerValue = Float.NEGATIVE_INFINITY} or {@code upperValue = Float.POSITIVE_INFINITY}.
|
* by setting {@code lowerValue = Float.NEGATIVE_INFINITY} or {@code upperValue = Float.POSITIVE_INFINITY}.
|
||||||
* <p> Ranges are inclusive. For exclusive ranges, pass {@code Math#nextUp(lowerValue)}
|
* <p> Ranges are inclusive. For exclusive ranges, pass {@link #nextUp(float) nextUp(lowerValue)}
|
||||||
* or {@code Math.nextDown(upperValue)}.
|
* or {@link #nextUp(float) nextDown(upperValue)}.
|
||||||
* <p>
|
* <p>
|
||||||
* Range comparisons are consistent with {@link Float#compareTo(Float)}.
|
* Range comparisons are consistent with {@link Float#compareTo(Float)}.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2052,4 +2052,32 @@ public class TestPointQueries extends LuceneTestCase {
|
||||||
});
|
});
|
||||||
assertEquals("lowerPoint has length=4 but upperPoint has different length=8", e.getMessage());
|
assertEquals("lowerPoint has length=4 but upperPoint has different length=8", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testNextUp() {
|
||||||
|
assertTrue(Double.compare(0d, DoublePoint.nextUp(-0d)) == 0);
|
||||||
|
assertTrue(Double.compare(Double.MIN_VALUE, DoublePoint.nextUp(0d)) == 0);
|
||||||
|
assertTrue(Double.compare(Double.POSITIVE_INFINITY, DoublePoint.nextUp(Double.MAX_VALUE)) == 0);
|
||||||
|
assertTrue(Double.compare(Double.POSITIVE_INFINITY, DoublePoint.nextUp(Double.POSITIVE_INFINITY)) == 0);
|
||||||
|
assertTrue(Double.compare(-Double.MAX_VALUE, DoublePoint.nextUp(Double.NEGATIVE_INFINITY)) == 0);
|
||||||
|
|
||||||
|
assertTrue(Float.compare(0f, FloatPoint.nextUp(-0f)) == 0);
|
||||||
|
assertTrue(Float.compare(Float.MIN_VALUE, FloatPoint.nextUp(0f)) == 0);
|
||||||
|
assertTrue(Float.compare(Float.POSITIVE_INFINITY, FloatPoint.nextUp(Float.MAX_VALUE)) == 0);
|
||||||
|
assertTrue(Float.compare(Float.POSITIVE_INFINITY, FloatPoint.nextUp(Float.POSITIVE_INFINITY)) == 0);
|
||||||
|
assertTrue(Float.compare(-Float.MAX_VALUE, FloatPoint.nextUp(Float.NEGATIVE_INFINITY)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testNextDown() {
|
||||||
|
assertTrue(Double.compare(-0d, DoublePoint.nextDown(0d)) == 0);
|
||||||
|
assertTrue(Double.compare(-Double.MIN_VALUE, DoublePoint.nextDown(-0d)) == 0);
|
||||||
|
assertTrue(Double.compare(Double.NEGATIVE_INFINITY, DoublePoint.nextDown(-Double.MAX_VALUE)) == 0);
|
||||||
|
assertTrue(Double.compare(Double.NEGATIVE_INFINITY, DoublePoint.nextDown(Double.NEGATIVE_INFINITY)) == 0);
|
||||||
|
assertTrue(Double.compare(Double.MAX_VALUE, DoublePoint.nextDown(Double.POSITIVE_INFINITY)) == 0);
|
||||||
|
|
||||||
|
assertTrue(Float.compare(-0f, FloatPoint.nextDown(0f)) == 0);
|
||||||
|
assertTrue(Float.compare(-Float.MIN_VALUE, FloatPoint.nextDown(-0f)) == 0);
|
||||||
|
assertTrue(Float.compare(Float.NEGATIVE_INFINITY, FloatPoint.nextDown(-Float.MAX_VALUE)) == 0);
|
||||||
|
assertTrue(Float.compare(Float.NEGATIVE_INFINITY, FloatPoint.nextDown(Float.NEGATIVE_INFINITY)) == 0);
|
||||||
|
assertTrue(Float.compare(Float.MAX_VALUE, FloatPoint.nextDown(Float.POSITIVE_INFINITY)) == 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -229,6 +229,7 @@ public class TestHalfFloatPoint extends LuceneTestCase {
|
||||||
// values that cannot be exactly represented as a half float
|
// values that cannot be exactly represented as a half float
|
||||||
assertEquals(HalfFloatPoint.nextUp(0f), HalfFloatPoint.nextUp(Float.MIN_VALUE), 0f);
|
assertEquals(HalfFloatPoint.nextUp(0f), HalfFloatPoint.nextUp(Float.MIN_VALUE), 0f);
|
||||||
assertEquals(Float.floatToIntBits(-0f), Float.floatToIntBits(HalfFloatPoint.nextUp(-Float.MIN_VALUE)));
|
assertEquals(Float.floatToIntBits(-0f), Float.floatToIntBits(HalfFloatPoint.nextUp(-Float.MIN_VALUE)));
|
||||||
|
assertEquals(Float.floatToIntBits(0f), Float.floatToIntBits(HalfFloatPoint.nextUp(-0f)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testNextDown() {
|
public void testNextDown() {
|
||||||
|
@ -239,5 +240,6 @@ public class TestHalfFloatPoint extends LuceneTestCase {
|
||||||
// values that cannot be exactly represented as a half float
|
// values that cannot be exactly represented as a half float
|
||||||
assertEquals(Float.floatToIntBits(0f), Float.floatToIntBits(HalfFloatPoint.nextDown(Float.MIN_VALUE)));
|
assertEquals(Float.floatToIntBits(0f), Float.floatToIntBits(HalfFloatPoint.nextDown(Float.MIN_VALUE)));
|
||||||
assertEquals(HalfFloatPoint.nextDown(-0f), HalfFloatPoint.nextDown(-Float.MIN_VALUE), 0f);
|
assertEquals(HalfFloatPoint.nextDown(-0f), HalfFloatPoint.nextDown(-Float.MIN_VALUE), 0f);
|
||||||
|
assertEquals(Float.floatToIntBits(-0f), Float.floatToIntBits(HalfFloatPoint.nextDown(+0f)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue