这段代码可以很好地计算阶乘,但是用浮点数或十进制数给出错误的答案

    fun factorial(number: BigDecimal): BigDecimal {
        if (number >= BigDecimal(3000)) {
            is_infinity = true
            return BigDecimal.ZERO
        }
        return if (number < BigDecimal.ZERO) {
            domain_error = true
            BigDecimal.ZERO
        } else {
            val decimalPartOfNumber = number.toDouble() - number.toInt()
            if (decimalPartOfNumber == 0.0) {
                var factorial = BigInteger("1")
                for (i in 1..number.toInt()) {
                    factorial *= i.toBigInteger()
                }
                factorial.toBigDecimal()
            } else gammaLanczos(number + BigDecimal.ONE)
        }
    }

    private fun gammaLanczos(x: BigDecimal): BigDecimal {
        // https://rosettacode.org/wiki/Gamma_function
        var xx = x
        val p = doubleArrayOf(
            0.9999999999998099,
            676.5203681218851,
            -1259.1392167224028,
            771.3234287776531,
            -176.6150291621406,
            12.507343278686905,
            -0.13857109526572012,
            9.984369578019572E-6,
            1.5056327351493116e-7
        )
        val g = BigDecimal(7)
        if (xx < BigDecimal(0.5)) return (Math.PI / (sin(Math.PI * xx.toDouble()) * gammaLanczos(BigDecimal(1.0 - xx.toDouble())).toDouble())).toBigDecimal()
        xx--
        var a = p[0]
        val t = xx + g + BigDecimal(0.5)
        for (i in 1 until p.size) a += p[i] / (xx.toDouble() + i)
        return (sqrt(2.0 * Math.PI) * t.toDouble().pow(xx.toInt() + 0.5) * exp(-t.toDouble()) * a).toBigDecimal()
    }

对于下面的代码,测试在运行9个代码后失败,

@Test
    fun sqrt() {

        val result =  NumberFormatter.factorial(BigDecimal(3.03))
        assertEquals(6.23120891259, result.toFloat())
    }

得到这个预期:6.23120891259但是:5.8062997<><>

有人能帮我吗.谢谢

推荐答案

由于BigDecorator和double之间的转换,代码有精度损失.你可以更新gammaLanczos,

fun gammaLanczos(x: BigDecimal): BigDecimal {
// Lanczos approximation parameters
   val p = arrayOf(
       676.5203681218851,
      -1259.1392167224028,
      771.3234287776531,
      -176.6150291621406,
      12.507343278686905,
      -0.13857109526572012,
      9.984369578019572e-6,
      1.5056327351493116e-7
  )
  val g = 7.0
  var z = x.toDouble() - 1.0

  var a = 0.99999999999980993
  for (i in p.indices) {
      a += p[i] / (z + i + 1)
  }

  val t = z + g + 0.5
  val sqrtTwoPi = sqrt(2.0 * PI)
  val firstPart = sqrtTwoPi * t.pow(z + 0.5) * exp(-t)
  val result = firstPart * a

  return BigDecimal(result, MathContext.DECIMAL64)
}

fun BigDecimal.pow(exponent: Double): BigDecimal {
   return this.toDouble().pow(exponent).toBigDecimal(MathContext.DECIMAL64)
}

Kotlin相关问答推荐

Fleet无法从构建文件自动重新加载更改错误'

如何访问方法引用的接收者?

Kotlin:有限的并行性并不是限制并行性

如何接受任何派生类KClass

从 Kotlin 的父类获取函数注解

Kotlin 基于参数类型的返回类型推断

按钮无法在 Android Studio 上打开新活动

Kotlin 协程按顺序执行,但仅在生产机器上执行

如何在 kotlin 中创建自定义迭代器并添加到现有类?

测试协程和线程之间的差异,我在kotlin中使用线程时无法得到OOM错误

正则表达式 FindAll 不打印结果 Kotlin

为什么我在使用 Jetpack Compose clickable-Modifier 时收到后端内部错误:Exception during IR lowering error?

Android Studio 4.0.0 Java 8 库在 D8 和 R8 构建错误中脱糖

androidx.core:core-ktx:1.0.0 小部件包丢失

TornadoFX 中设置 PrimaryStage 或 Scene 属性的方法

项目未与 Gradle 链接

使用导航组件在不同的图形之间导航

可以在函数参数中使用解构吗?

如何根据ArrayList的对象属性值从中获取最小/最大值?

Kotlin,什么时候按map授权?