3

在 Scalacheck 中发现了一个问题,它arbitrary[BigDecimal]生成BigDecimal无法转换为Strings 然后再转换为 sBigDecimal的 s,我正在尝试与创建者一起寻找解决方案,但我不确定MathContexts 是如何来的玩。

原始生成器如下所示:

/** Arbitrary BigDecimal */
implicit lazy val arbBigDecimal: Arbitrary[BigDecimal] = {
  import java.math.MathContext._
  val mcGen = oneOf(UNLIMITED, DECIMAL32, DECIMAL64, DECIMAL128)
  val bdGen = for {
    x <- arbBigInt.arbitrary
    mc <- mcGen
    limit <- const(if(mc == UNLIMITED) 0 else math.max(x.abs.toString.length - mc.getPrecision, 0))
    scale <- Gen.chooseNum(Int.MinValue + limit , Int.MaxValue)
  } yield {
    try {
      BigDecimal(x, scale, mc)
    } catch {
      case ae: java.lang.ArithmeticException => BigDecimal(x, scale, UNLIMITED) // Handle the case where scale/precision conflict
    }
  }
  Arbitrary(bdGen)
}

问题在于BigDecimal使用的构造函数反转了scale参数的符号,从而使Int.MinValue变成scale大于 2^32 -1。

scala> val orig = BigDecimal(BigInt("-28334198897217871282176"), -2147483640, UNLIMITED)
orig: scala.math.BigDecimal = -2.8334198897217871282176E+2147483662

scala> BigDecimal(orig.toString)
java.lang.NumberFormatException
  at java.math.BigDecimal.<init>(BigDecimal.java:554)
  at java.math.BigDecimal.<init>(BigDecimal.java:383)
  at java.math.BigDecimal.<init>(BigDecimal.java:806)
  at scala.math.BigDecimal$.exact(BigDecimal.scala:125)
  at scala.math.BigDecimal$.apply(BigDecimal.scala:283)
  ... 33 elided

修复的核心是通过 中的位数增加下限unscaledVal,但我只是想到了一种方法来做到这一点MathContext.UNLIMITED。如果我们这样做,我担心我们会错过生成器的鲁棒性:

lazy val genBigDecimal: Gen[BigDecimal] = for {
  unscaledVal <- arbitrary[BigInt]
  scale <- Gen.chooseNum(Int.MinValue + unscaledVal.abs.toString.length, Int.MaxValue)
} yield BigDecimal(unscaledVal, scale)

那么,如果我们想继续使用其他MathContext的,我们必须做些什么来确保我们正确地使用它们呢?

4

0 回答 0