小数到粗俗分数,Kotlin Android
Decimal to vulgar fraction, Kotlin Android
我一直在尝试将我的 Swift 方法转换为 Kotlin,但在这里没有得到任何帮助:
Decimal to vulgar fraction conversion method- need help converting from Swift to Kotlin
我想我会稍微改变一下我的问题,看看是否能得到一些帮助。我需要有关代码反向 engineering/explanation 的帮助,以便我可以自己进行转换。反正我会通过这种方式学到更多。
如果有兴趣,完整的 code/story 链接在上面。
我几乎想要付钱给自由职业者来帮助解决这个问题。请帮忙 :)
此外,您可能需要知道有一个数组,其中包含此方法舍入到的小数英寸的上标和下标输出。
需要解释以下几行:
val whole = number.toInt() // Of course i know what this does :)
val sign = if (whole < 0) -1 else 1 // I converted this myself and believe this is correct Kotlin
val fraction = number - whole.toDouble() // And I know what this does
// need explanation from here down
for (i in 1..fractions.count()) {
if (abs(fraction) > (fractions[i].1 + fractions[i - 1].1) / 2) {
if ((fractions[i - 1].1) == (1.0)) run {
return@run Pair("${whole + sign}", (whole + sign).toDouble())
} else {
return ("$whole" $fractions[i - 1].0, ${whole.toDouble() + (sign.toDouble() * fractions[i - 1].1))
}
}
}
一般来说,我倾向于把这样的计算函数写成kotlin的扩展function/property,因为这样会增加可用性。
NumberExt.kt
package ***
import kotlin.math.abs
/**
* @author aminography
*/
val Double.vulgarFraction: Pair<String, Double>
get() {
val whole = toInt()
val sign = if (whole < 0) -1 else 1
val fraction = this - whole
for (i in 1 until fractions.size) {
if (abs(fraction) > (fractionValues[i] + fractionValues[i - 1]) / 2) {
return if (fractionValues[i - 1] == 1.0) {
"${whole + sign}" to (whole + sign).toDouble()
} else {
"$whole ${fractions[i - 1]}" to whole + sign * fractionValues[i - 1]
}
}
}
return "$whole" to whole.toDouble()
}
val Float.vulgarFraction: Pair<String, Double>
get() = toDouble().vulgarFraction
private val fractions = arrayOf(
"", // 16/16
"\u00B9\u2075/\u2081\u2086", // 15/16
"\u215E", // 7/8
"\u00B9\u00B3/\u2081\u2086", // 13/16
"\u00BE", // 3/4
"\u00B9\u00B9/\u2081\u2086", // 11/16
"\u215D", // 5/8
"\u2079/\u2081\u2086", // 9/16
"\u00BD", // 1/2
"\u2077/\u2081\u2086", // 7/16
"\u215C", // 3/8
"\u2075/\u2081\u2086", // 5/16
"\u00BC", // 1/4
"\u00B3/\u2081\u2086", // 3/16
"\u215B", // 1/8
"\u00B9/\u2081\u2086", // 1/16
"" // 0/16
)
private val fractionValues = arrayOf(
1.0,
15.0 / 16, 7.0 / 8, 13.0 / 16, 3.0 / 4, 11.0 / 16,
5.0 / 8, 9.0 / 16, 1.0 / 2, 7.0 / 16, 3.0 / 8,
5.0 / 16, 1.0 / 4, 3.0 / 16, 1.0 / 8, 1.0 / 16,
0.0
)
测试
val rand = java.util.Random()
repeat(10) {
val sign = if (rand.nextBoolean()) 1 else -1
val number = rand.nextDouble() * rand.nextInt(100) * sign
val vulgar = number.vulgarFraction
println("Number: $number , Vulgar: ${vulgar.first} , Rounded: ${vulgar.second}")
}
输出:
Number: 17.88674468660217 , Vulgar: 17 ⅞ , Rounded: 17.875
Number: -56.98489542592821 , Vulgar: -57 , Rounded: -57.0
Number: 39.275953137210614 , Vulgar: 39 ¼ , Rounded: 39.25
Number: 13.422939071442359 , Vulgar: 13 ⁷/₁₆ , Rounded: 13.4375
Number: -56.70735924226373 , Vulgar: -56 ¹¹/₁₆ , Rounded: -56.6875
Number: 22.657555818202972 , Vulgar: 22 ¹¹/₁₆ , Rounded: 22.6875
Number: 2.951680466645306 , Vulgar: 2 ¹⁵/₁₆ , Rounded: 2.9375
Number: -8.8311628631306 , Vulgar: -8 ¹³/₁₆ , Rounded: -8.8125
Number: 28.639946409572655 , Vulgar: 28 ⅝ , Rounded: 28.625
Number: -28.439447873884085 , Vulgar: -28 ⁷/₁₆ , Rounded: -28.4375
说明
整体逻辑解释的有点难,我会尽量讲清楚一点。请注意,在下面的代码片段中,为了简化,我将 fractionValues[i - 1]
替换为 fractionValue
。
// First look at the 'fractions' array. It starts from 16/16=1 down to 0/16=0.
// So it covers all the possible 16 cases for dividing a number by 16.
// Note that 16/16=1 and 0/16=0 are the same in terms of division residual.
for (i in 1 until fractions.size) {
// Here, we are searching for the proper fraction that is the nearest one to the
// actual division residual.
// So, '|fraction| > (fractionValues[i] + fractionValues[i - 1]) / 2' means
// that the fraction is closer to the greater one in the 'fractionValues' array
// (i.e. 'fractionValues[i - 1]').
// Consider that we always want to find the proper 'fractionValues[i - 1]' and not
// 'fractionValues[i]' (According to the index of the 'for' loop which starts
// from 1, and not 0).
if (abs(fraction) > (fractionValues[i] + fractionValues[i - 1]) / 2) {
val fractionValue = fractionValues[i - 1]
// Here we've found the proper fraction value (i.e. 'fractionValue').
return if (fractionValue == 1.0) {
// 'fractionValue == 1.0' means that the actual division residual was greater
// than 15/16 but closer to 16/16=1. So the final value should be rounded to
// the nearest integer. Consider that in this case, the nearest integer for a
// positive number is one more and for a negative number, one less. Finally,
// the summation with 'sign' does it for us :)
"${whole + sign}" to (whole + sign).toDouble()
} else {
// Here we have 'fractionValue < 1.0'. The only thing is to calculate the
// rounded value which is the sum of 'whole' and the discovered 'fractionValue'.
// As the value could be negative, by multiplying the 'sign' to the
// 'fractionValue', we will be sure that the summation is always correct.
"$whole $fractionValue" to whole + sign * fractionValue
}
}
}
// Finally, if we are not able to find a proper 'fractionValue' for the input number,
// it means the number had an integer value.
return "$whole" to whole.toDouble()
我一直在尝试将我的 Swift 方法转换为 Kotlin,但在这里没有得到任何帮助: Decimal to vulgar fraction conversion method- need help converting from Swift to Kotlin
我想我会稍微改变一下我的问题,看看是否能得到一些帮助。我需要有关代码反向 engineering/explanation 的帮助,以便我可以自己进行转换。反正我会通过这种方式学到更多。
如果有兴趣,完整的 code/story 链接在上面。 我几乎想要付钱给自由职业者来帮助解决这个问题。请帮忙 :) 此外,您可能需要知道有一个数组,其中包含此方法舍入到的小数英寸的上标和下标输出。 需要解释以下几行:
val whole = number.toInt() // Of course i know what this does :)
val sign = if (whole < 0) -1 else 1 // I converted this myself and believe this is correct Kotlin
val fraction = number - whole.toDouble() // And I know what this does
// need explanation from here down
for (i in 1..fractions.count()) {
if (abs(fraction) > (fractions[i].1 + fractions[i - 1].1) / 2) {
if ((fractions[i - 1].1) == (1.0)) run {
return@run Pair("${whole + sign}", (whole + sign).toDouble())
} else {
return ("$whole" $fractions[i - 1].0, ${whole.toDouble() + (sign.toDouble() * fractions[i - 1].1))
}
}
}
一般来说,我倾向于把这样的计算函数写成kotlin的扩展function/property,因为这样会增加可用性。
NumberExt.kt
package ***
import kotlin.math.abs
/**
* @author aminography
*/
val Double.vulgarFraction: Pair<String, Double>
get() {
val whole = toInt()
val sign = if (whole < 0) -1 else 1
val fraction = this - whole
for (i in 1 until fractions.size) {
if (abs(fraction) > (fractionValues[i] + fractionValues[i - 1]) / 2) {
return if (fractionValues[i - 1] == 1.0) {
"${whole + sign}" to (whole + sign).toDouble()
} else {
"$whole ${fractions[i - 1]}" to whole + sign * fractionValues[i - 1]
}
}
}
return "$whole" to whole.toDouble()
}
val Float.vulgarFraction: Pair<String, Double>
get() = toDouble().vulgarFraction
private val fractions = arrayOf(
"", // 16/16
"\u00B9\u2075/\u2081\u2086", // 15/16
"\u215E", // 7/8
"\u00B9\u00B3/\u2081\u2086", // 13/16
"\u00BE", // 3/4
"\u00B9\u00B9/\u2081\u2086", // 11/16
"\u215D", // 5/8
"\u2079/\u2081\u2086", // 9/16
"\u00BD", // 1/2
"\u2077/\u2081\u2086", // 7/16
"\u215C", // 3/8
"\u2075/\u2081\u2086", // 5/16
"\u00BC", // 1/4
"\u00B3/\u2081\u2086", // 3/16
"\u215B", // 1/8
"\u00B9/\u2081\u2086", // 1/16
"" // 0/16
)
private val fractionValues = arrayOf(
1.0,
15.0 / 16, 7.0 / 8, 13.0 / 16, 3.0 / 4, 11.0 / 16,
5.0 / 8, 9.0 / 16, 1.0 / 2, 7.0 / 16, 3.0 / 8,
5.0 / 16, 1.0 / 4, 3.0 / 16, 1.0 / 8, 1.0 / 16,
0.0
)
测试
val rand = java.util.Random()
repeat(10) {
val sign = if (rand.nextBoolean()) 1 else -1
val number = rand.nextDouble() * rand.nextInt(100) * sign
val vulgar = number.vulgarFraction
println("Number: $number , Vulgar: ${vulgar.first} , Rounded: ${vulgar.second}")
}
输出:
Number: 17.88674468660217 , Vulgar: 17 ⅞ , Rounded: 17.875
Number: -56.98489542592821 , Vulgar: -57 , Rounded: -57.0
Number: 39.275953137210614 , Vulgar: 39 ¼ , Rounded: 39.25
Number: 13.422939071442359 , Vulgar: 13 ⁷/₁₆ , Rounded: 13.4375
Number: -56.70735924226373 , Vulgar: -56 ¹¹/₁₆ , Rounded: -56.6875
Number: 22.657555818202972 , Vulgar: 22 ¹¹/₁₆ , Rounded: 22.6875
Number: 2.951680466645306 , Vulgar: 2 ¹⁵/₁₆ , Rounded: 2.9375
Number: -8.8311628631306 , Vulgar: -8 ¹³/₁₆ , Rounded: -8.8125
Number: 28.639946409572655 , Vulgar: 28 ⅝ , Rounded: 28.625
Number: -28.439447873884085 , Vulgar: -28 ⁷/₁₆ , Rounded: -28.4375
说明
整体逻辑解释的有点难,我会尽量讲清楚一点。请注意,在下面的代码片段中,为了简化,我将 fractionValues[i - 1]
替换为 fractionValue
。
// First look at the 'fractions' array. It starts from 16/16=1 down to 0/16=0.
// So it covers all the possible 16 cases for dividing a number by 16.
// Note that 16/16=1 and 0/16=0 are the same in terms of division residual.
for (i in 1 until fractions.size) {
// Here, we are searching for the proper fraction that is the nearest one to the
// actual division residual.
// So, '|fraction| > (fractionValues[i] + fractionValues[i - 1]) / 2' means
// that the fraction is closer to the greater one in the 'fractionValues' array
// (i.e. 'fractionValues[i - 1]').
// Consider that we always want to find the proper 'fractionValues[i - 1]' and not
// 'fractionValues[i]' (According to the index of the 'for' loop which starts
// from 1, and not 0).
if (abs(fraction) > (fractionValues[i] + fractionValues[i - 1]) / 2) {
val fractionValue = fractionValues[i - 1]
// Here we've found the proper fraction value (i.e. 'fractionValue').
return if (fractionValue == 1.0) {
// 'fractionValue == 1.0' means that the actual division residual was greater
// than 15/16 but closer to 16/16=1. So the final value should be rounded to
// the nearest integer. Consider that in this case, the nearest integer for a
// positive number is one more and for a negative number, one less. Finally,
// the summation with 'sign' does it for us :)
"${whole + sign}" to (whole + sign).toDouble()
} else {
// Here we have 'fractionValue < 1.0'. The only thing is to calculate the
// rounded value which is the sum of 'whole' and the discovered 'fractionValue'.
// As the value could be negative, by multiplying the 'sign' to the
// 'fractionValue', we will be sure that the summation is always correct.
"$whole $fractionValue" to whole + sign * fractionValue
}
}
}
// Finally, if we are not able to find a proper 'fractionValue' for the input number,
// it means the number had an integer value.
return "$whole" to whole.toDouble()