Skip to content

Commit

Permalink
Improve Precision for scaled_float (#37169)
Browse files Browse the repository at this point in the history
* Use `toString` and `Bigdecimal` parsing to get intuitive behaviour for `scaled_float` as discussed in #32570
* Closes #32570
  • Loading branch information
original-brownbear committed Jan 11, 2019
1 parent c4bb675 commit 70d5943
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
import org.joda.time.DateTimeZone;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
Expand Down Expand Up @@ -228,8 +229,7 @@ public Query existsQuery(QueryShardContext context) {
@Override
public Query termQuery(Object value, QueryShardContext context) {
failIfNotIndexed();
double queryValue = parse(value);
long scaledValue = Math.round(queryValue * scalingFactor);
long scaledValue = Math.round(scale(value));
Query query = NumberFieldMapper.NumberType.LONG.termQuery(name(), scaledValue);
if (boost() != 1f) {
query = new BoostQuery(query, boost());
Expand All @@ -242,8 +242,7 @@ public Query termsQuery(List<?> values, QueryShardContext context) {
failIfNotIndexed();
List<Long> scaledValues = new ArrayList<>(values.size());
for (Object value : values) {
double queryValue = parse(value);
long scaledValue = Math.round(queryValue * scalingFactor);
long scaledValue = Math.round(scale(value));
scaledValues.add(scaledValue);
}
Query query = NumberFieldMapper.NumberType.LONG.termsQuery(name(), Collections.unmodifiableList(scaledValues));
Expand All @@ -258,15 +257,15 @@ public Query rangeQuery(Object lowerTerm, Object upperTerm, boolean includeLower
failIfNotIndexed();
Long lo = null;
if (lowerTerm != null) {
double dValue = parse(lowerTerm) * scalingFactor;
double dValue = scale(lowerTerm);
if (includeLower == false) {
dValue = Math.nextUp(dValue);
}
lo = Math.round(Math.ceil(dValue));
}
Long hi = null;
if (upperTerm != null) {
double dValue = parse(upperTerm) * scalingFactor;
double dValue = scale(upperTerm);
if (includeUpper == false) {
dValue = Math.nextDown(dValue);
}
Expand Down Expand Up @@ -327,6 +326,19 @@ public boolean equals(Object o) {
public int hashCode() {
return 31 * super.hashCode() + Double.hashCode(scalingFactor);
}

/**
* Parses input value and multiplies it with the scaling factor.
* Uses the round-trip of creating a {@link BigDecimal} from the stringified {@code double}
* input to ensure intuitively exact floating point operations.
* (e.g. for a scaling factor of 100, JVM behaviour results in {@code 79.99D * 100 ==> 7998.99..} compared to
* {@code scale(79.99) ==> 7999})
* @param input Input value to parse floating point num from
* @return Scaled value
*/
private double scale(Object input) {
return new BigDecimal(Double.toString(parse(input))).multiply(BigDecimal.valueOf(scalingFactor)).doubleValue();
}
}

private Boolean includeInAll;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ public void testRoundsUpperBoundCorrectly() {
assertEquals("scaled_float:[-9223372036854775808 TO 10]", scaledFloatQ.toString());
scaledFloatQ = ft.rangeQuery(null, 0.105, true, true, null);
assertEquals("scaled_float:[-9223372036854775808 TO 10]", scaledFloatQ.toString());
scaledFloatQ = ft.rangeQuery(null, 79.99, true, true, null);
assertEquals("scaled_float:[-9223372036854775808 TO 7999]", scaledFloatQ.toString());
}

public void testRoundsLowerBoundCorrectly() {
Expand Down

0 comments on commit 70d5943

Please sign in to comment.