jqwik链式Double生成器scale异常 咨询scale参数含义及设置方法
报错场景
使用jqwik链式double生成器时抛出如下异常:
java.util.concurrent.ExecutionException: net.jqwik.api.JqwikException: Decimal value -1.6099999999999999 cannot be represented with scale 4.
使用的生成器代码:
@Provide("close doubles") Arbitrary<Tuple.Tuple2<Double,Double>> closeDoubles(@ForAll() Double aDouble) { return Arbitraries.doubles() .between(aDouble-2.5, aDouble+2.5) .withSpecialValue(aDouble) .ofScale(4) .map(num ->Tuple.of(aDouble,num)); }
目标需求为生成两个差值不超过2.5的相近double值。
ofScale参数含义 - 该参数用于约束生成的浮点数,必须能够无歧义表示为小数点后最多N位的十进制数,设置为4时,所有生成值转换为十进制后小数位不会超过4位,再转换为double类型返回。
- 报错的核心原因:外层通过
@ForAll注入的aDouble是无精度约束的随机double,做aDouble-2.5这类算术运算时会出现原生浮点精度损失,生成类似-1.6099999999999999这类无法被精确舍入到4位小数的边界值,和ofScale(4)的约束直接冲突,触发异常。
正确配置方案
方案1:全链路统一精度约束(需要固定小数位时使用)
不要通过方法参数注入无约束的基准double,而是在生成器内部先定义和后续规则一致的基准值生成逻辑,通过flatMap链式生成,保证所有参与计算的数值都符合精度要求:
@Provide("close doubles") Arbitrary<Tuple.Tuple2<Double,Double>> closeDoubles() { // 基准值同样约束为4位小数,避免计算边界时出现精度溢出 Arbitrary<Double> baseArb = Arbitraries.doubles().ofScale(4); return baseArb.flatMap(baseVal -> Arbitraries.doubles() .between(baseVal - 2.5, baseVal + 2.5) .ofScale(4) .withSpecialValue(baseVal) .map(closeVal -> Tuple.of(baseVal, closeVal)) ); }
方案2:移除不必要的精度约束(无小数位要求时使用)
如果业务场景不需要强制固定小数位数,直接删除ofScale(4)调用即可,jqwik默认的double生成器会自动处理浮点边界问题,不会触发这类精度异常,同时完全满足“两值差值不超过2.5”的需求:
@Provide("close doubles") Arbitrary<Tuple.Tuple2<Double,Double>> closeDoubles(@ForAll Double aDouble) { return Arbitraries.doubles() .between(aDouble - 2.5, aDouble + 2.5) .withSpecialValue(aDouble) .map(num -> Tuple.of(aDouble, num)); }
内容的提问来源于stack exchange,提问作者Antonin
相关产品推荐
相关产品推荐

