I think gremlin should handle this case. It's a matter of setting the
MathContext precision. I was trying to reproduce this in the shell but
couldn't. Here's why and what groovy does:
public Number divideImpl(Number left, Number right) {
BigDecimal bigLeft = toBigDecimal(left);
BigDecimal bigRight = toBigDecimal(right);
try {
return bigLeft.divide(bigRight);
} catch (ArithmeticException e) {
// set a DEFAULT precision if otherwise non-terminating
int precision = Math.max(bigLeft.precision(),
bigRight.precision()) + DIVISION_EXTRA_PRECISION;
BigDecimal result = bigLeft.divide(bigRight, new
MathContext(precision));
int scale = Math.max(Math.max(bigLeft.scale(),
bigRight.scale()), DIVISION_MIN_SCALE);
if (result.scale() > scale) result = result.setScale(scale,
BigDecimal.ROUND_HALF_UP);
return result;
}
}
Robert Dale
On Tue, Jul 25, 2017 at 7:48 AM, Stephen Mallette <[email protected]>
wrote:
> Dan "The Stroke" LaRocque gave me some gory details on groovy's handling of
> decimals/numbers which can make sack() do this:
>
> gremlin> g.withSack(2).V().sack(div).by(constant(3.0)).sack()
> Non-terminating decimal expansion; no exact representable decimal result.
> Type ':help' or ':h' for help.
> Display stack trace? [yN]y
> java.lang.ArithmeticException: Non-terminating decimal expansion; no exact
> representable decimal result.
> at java.math.BigDecimal.divide(BigDecimal.java:1690)
> at
> org.apache.tinkerpop.gremlin.process.traversal.
> NumberHelper.lambda$static$45(NumberHelper.java:132)
> at
> org.apache.tinkerpop.gremlin.process.traversal.
> NumberHelper.div(NumberHelper.java:219)
> at
> org.apache.tinkerpop.gremlin.process.traversal.
> NumberHelper.div(NumberHelper.java:214)
> at
> org.apache.tinkerpop.gremlin.process.traversal.Operator$4.
> apply(Operator.java:47)
> at
> org.apache.tinkerpop.gremlin.process.traversal.step.
> sideEffect.SackValueStep.sideEffect(SackValueStep.java:60)
> at
> org.apache.tinkerpop.gremlin.process.traversal.step.
> sideEffect.SideEffectStep.processNextStart(SideEffectStep.java:39)
> at
> org.apache.tinkerpop.gremlin.process.traversal.step.util.
> AbstractStep.hasNext(AbstractStep.java:143)
> at
> org.apache.tinkerpop.gremlin.process.traversal.step.util.
> ExpandableStepIterator.next(ExpandableStepIterator.java:50)
> at
> org.apache.tinkerpop.gremlin.process.traversal.step.map.
> MapStep.processNextStart(MapStep.java:36)
> at
> org.apache.tinkerpop.gremlin.process.traversal.step.util.
> AbstractStep.hasNext(AbstractStep.java:143)
> at
> org.apache.tinkerpop.gremlin.process.traversal.util.
> DefaultTraversal.hasNext(DefaultTraversal.java:184)
> at
> org.apache.tinkerpop.gremlin.console.Console$_closure3.
> doCall(Console.groovy:237)
> at sun.reflect.GeneratedMethodAccessor39.invoke(Unknown Source)
> ...
> at
> org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnSuperN(
> ScriptBytecodeAdapter.java:132)
> at
> org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnSuper0(
> ScriptBytecodeAdapter.java:152)
> at
> org.codehaus.groovy.tools.shell.InteractiveShellRunner.
> run(InteractiveShellRunner.groovy:83)
> at
> org.codehaus.groovy.vmplugin.v7.IndyInterface.selectMethod(
> IndyInterface.java:232)
> at org.apache.tinkerpop.gremlin.console.Console.<init>(Console.groovy:169)
> at
> org.codehaus.groovy.vmplugin.v7.IndyInterface.selectMethod(
> IndyInterface.java:232)
> at org.apache.tinkerpop.gremlin.console.Console.main(Console.groovy:478)
>
> this does work well if the Gremlin has more explicit typing:
>
> gremlin> g.withSack(2).V().sack(div).by(constant(3.0d)).sack()
> ==>0.6666666666666666
> ==>0.6666666666666666
> ==>0.6666666666666666
> ==>0.6666666666666666
> ==>0.6666666666666666
> ==>0.6666666666666666
> gremlin> g.withSack(2d).V().sack(div).by(constant(3)).sack()
> ==>0.6666666666666666
> ==>0.6666666666666666
> ==>0.6666666666666666
> ==>0.6666666666666666
> ==>0.6666666666666666
> ==>0.6666666666666666
> gremlin> g.withSack(2).V().sack(div).by(constant(3)).sack()
> ==>0
> ==>0
> ==>0
> ==>0
> ==>0
> ==>0
>
> Is this something we can make nicer? Create a ticket?
>