在 Kotlin 中舍入
Rounding in Kotlin
我有Kotlin Double,希望return Int,特别四舍五入。
166.66 -> 166
166.99 -> 167
文档中没有合适的内容。我需要介于 DOWN 和 CEILING
之间的东西
Rounding in Kotlin
val df = DecimalFormat("#")
df.roundingMode = RoundingMode.DOWN
println(df.format(166.99))
继续
这个套路的目的是计算出您需要购买多少瓶免税威士忌,这样比正常的商业街价格节省的钱就可以有效地支付您的假期费用。
您将获得高街价格 (normPrice)、免税折扣 (discount) 和假期费用。
例如,如果一瓶正常价格为 10 英镑,而免税折扣为 10%,则每瓶可节省 1 英镑。如果您的假期花费 500 英镑,那么您应该 return 的答案是 500。
所有输入均为整数。请return一个整数。向下舍入。
测试在这里:
assertEquals(166, dutyFree(12, 50, 1000))// I have a problem with rounding here
assertEquals(294, dutyFree(17, 10, 500))
assertEquals(357, dutyFree(24, 35, 3000))
assertEquals(60, dutyFree(377, 40, 9048))// And here
assertEquals(10, dutyFree(2479, 51, 13390))
我的解决方案是,但我不明白我应该如何正确舍入它:
fun dutyFree(normPrice: Int, discount:Int, hol:Int) : Int {
val priseWithDiscount: (Int, Int) -> Double = { a: Int, b: Int -> a*b/100.00}
val result = hol/priseWithDiscount.invoke(normPrice, discount)
return result.toInt()
}
这适用什么规则?如果 166.99 -> 167 你想舍入它,但如果你想遵循的规则是 166.66 -> 166 你想截断双。
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.math/truncate.html
四舍五入通常会得到最接近的整数 - 166.66
和 166.99
都会四舍五入到 170
,因为它们都高于 166.5
。这是正确的(也是预期的!)行为。但是 kata 告诉你向下舍入,所以用 toInt()
截断应该没问题 - 所以这两个最终都是 166
.
您 运行 遇到的问题是 floating-point 舍入错误。这是您遇到问题的那个:
assertEquals(60, dutyFree(377, 40, 9048))
哪个应该可以正常工作:
377 * 0.4 = 150.8
9048 / 150.8 = 60
但实际上:
println(377.0 * 0.4)
>> 150.8
println(9048.0 / 150.8)
>> 59.99999999999999
有更好的解释 here,但基本上由于 floating-point 数学运算的方式,有些数字您无法准确表示,最终会失去精度。这类似于十进制的 2/3
写成 0.6666667
的方式 - 最后的 7
是一个舍入误差,60
变成 59.9999999
也是如此
您可以尝试使用 BigDecimal
以获得更高的准确性,但这有点复杂 - 您可以改为添加误差范围以补偿舍入,方法是在结果中添加一个非常小的数字:
fun dutyFree(normPrice: Int, discount:Int, hol:Int) : Int {
// I just pressed 0 a few times, there's no calculation behind this number, it's just small
val roundingWindow = 0.000000001
val priseWithDiscount: (Int, Int) -> Double = { a: Int, b: Int -> a*b/100.00}
val result = hol/priseWithDiscount.invoke(normPrice, discount)
return (result + roundingWindow).toInt()
}
基本上,由于您无论如何都要向下舍入,这只会影响下一个整数下的 jussssst 数字,方法是将它们推到它上面,以便它们向下舍入到那个整数。如果调整太大,它会开始将更低的数字推到下一个整数,因此它们会在不应该的地方四舍五入
所以你必须使用一个小数字,这足以弥补那些微小的错误(你需要的确切数字称为 machine epsilon 但这是一个复杂的主题,这个只是一个“足够好”的修复,似乎适合这种情况)。当你这样做时,你所有的测试用例都会通过!
我有Kotlin Double,希望return Int,特别四舍五入。
166.66 -> 166
166.99 -> 167
文档中没有合适的内容。我需要介于 DOWN 和 CEILING
之间的东西Rounding in Kotlin
val df = DecimalFormat("#")
df.roundingMode = RoundingMode.DOWN
println(df.format(166.99))
继续
这个套路的目的是计算出您需要购买多少瓶免税威士忌,这样比正常的商业街价格节省的钱就可以有效地支付您的假期费用。
您将获得高街价格 (normPrice)、免税折扣 (discount) 和假期费用。
例如,如果一瓶正常价格为 10 英镑,而免税折扣为 10%,则每瓶可节省 1 英镑。如果您的假期花费 500 英镑,那么您应该 return 的答案是 500。
所有输入均为整数。请return一个整数。向下舍入。
测试在这里:
assertEquals(166, dutyFree(12, 50, 1000))// I have a problem with rounding here
assertEquals(294, dutyFree(17, 10, 500))
assertEquals(357, dutyFree(24, 35, 3000))
assertEquals(60, dutyFree(377, 40, 9048))// And here
assertEquals(10, dutyFree(2479, 51, 13390))
我的解决方案是,但我不明白我应该如何正确舍入它:
fun dutyFree(normPrice: Int, discount:Int, hol:Int) : Int {
val priseWithDiscount: (Int, Int) -> Double = { a: Int, b: Int -> a*b/100.00}
val result = hol/priseWithDiscount.invoke(normPrice, discount)
return result.toInt()
}
这适用什么规则?如果 166.99 -> 167 你想舍入它,但如果你想遵循的规则是 166.66 -> 166 你想截断双。 https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.math/truncate.html
四舍五入通常会得到最接近的整数 - 166.66
和 166.99
都会四舍五入到 170
,因为它们都高于 166.5
。这是正确的(也是预期的!)行为。但是 kata 告诉你向下舍入,所以用 toInt()
截断应该没问题 - 所以这两个最终都是 166
.
您 运行 遇到的问题是 floating-point 舍入错误。这是您遇到问题的那个:
assertEquals(60, dutyFree(377, 40, 9048))
哪个应该可以正常工作:
377 * 0.4 = 150.8
9048 / 150.8 = 60
但实际上:
println(377.0 * 0.4)
>> 150.8
println(9048.0 / 150.8)
>> 59.99999999999999
有更好的解释 here,但基本上由于 floating-point 数学运算的方式,有些数字您无法准确表示,最终会失去精度。这类似于十进制的 2/3
写成 0.6666667
的方式 - 最后的 7
是一个舍入误差,60
变成 59.9999999
也是如此
您可以尝试使用 BigDecimal
以获得更高的准确性,但这有点复杂 - 您可以改为添加误差范围以补偿舍入,方法是在结果中添加一个非常小的数字:
fun dutyFree(normPrice: Int, discount:Int, hol:Int) : Int {
// I just pressed 0 a few times, there's no calculation behind this number, it's just small
val roundingWindow = 0.000000001
val priseWithDiscount: (Int, Int) -> Double = { a: Int, b: Int -> a*b/100.00}
val result = hol/priseWithDiscount.invoke(normPrice, discount)
return (result + roundingWindow).toInt()
}
基本上,由于您无论如何都要向下舍入,这只会影响下一个整数下的 jussssst 数字,方法是将它们推到它上面,以便它们向下舍入到那个整数。如果调整太大,它会开始将更低的数字推到下一个整数,因此它们会在不应该的地方四舍五入
所以你必须使用一个小数字,这足以弥补那些微小的错误(你需要的确切数字称为 machine epsilon 但这是一个复杂的主题,这个只是一个“足够好”的修复,似乎适合这种情况)。当你这样做时,你所有的测试用例都会通过!