十进制转分数,Kotlin Android

3
我一直在尝试将我的Swift方法转换为Kotlin,但是在这里没有得到任何帮助:十进制数转化为分数的方法-需要将代码从Swift转换成Kotlin 我想我会稍微改变一下我的问题,看看能否得到帮助。我想要逆向工程/解释代码,以便我可以自己进行转换。这样我会更有所收获。
如果感兴趣,完整的代码/故事已经链接在上面。 我几乎到了想要支付自由职业者来帮忙的地步了。请帮帮我 :) 此外,您可能需要知道,该方法针对包含分数英寸超级和下标输出的数组进行舍入。 需要解释以下行的内容:
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))
        }
    }
}

1
检查了您的原始帖子。您最好尝试自己解释下半部分,以了解差距在哪里。由于您似乎是初学者,提示“您认为是数字小数点的十进制小数实际上是成员访问运算符”:如何在Swift中访问元组的成员?转换为Kotlin时,元组是否存在作为一种类型?我该如何访问Kotlin版本的成员? - Morrison Chang
抱歉,什么是分数? - Dmitry
@MorrisonChang,你真的做得很好!那正是我困惑的地方。谢谢!我现在会进一步查看 :) - Dmitry 对不起,我忘了提到这一点,完整的代码可以在我帖子顶部的链接中看到。“fractions”是一个由字符串和双精度浮点数组成的数组。它用于提供四舍五入到最近的1/16英寸的分数输出。例如:Pair("\u215D", 5/8) - RobbB
1个回答

3

一般来说,我倾向于将此类计算函数作为Kotlin扩展函数/属性编写,因为这样可增加其可用性。

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}")
}

输出:

数字:17.88674468660217,简化分数:17 ⅞,四舍五入:17.875
数字:-56.98489542592821,简化分数:-57,四舍五入:-57.0
数字:39.275953137210614,简化分数:39 ¼,四舍五入:39.25
数字:13.422939071442359,简化分数:13 ⁷/₁₆,四舍五入:13.4375
数字:-56.70735924226373,简化分数:-56 ¹¹/₁₆,四舍五入:-56.6875
数字:22.657555818202972,简化分数:22 ¹¹/₁₆,四舍五入:22.6875
数字:2.951680466645306,简化分数:2 ¹⁵/₁₆,四舍五入:2.9375
数字:-8.8311628631306,简化分数:-8 ¹³/₁₆,四舍五入:-8.8125
数字:28.639946409572655,简化分数:28 ⅝,四舍五入:28.625
数字:-28.439447873884085,简化分数:-28 ⁷/₁₆,四舍五入:-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()

有什么简单的方法可以将这个变成一个对象吗?我试着把所有的代码放到一个类里面来清理我的活动,但是 Kotlin 无法解决错误。这有点超出了我的能力范围。如果这不可能或者不容易实现,也没关系,它在活动中的表现非常好 :) - RobbB
1
正如我之前提到的,将这段代码放在一个文件中是更好的方式,例如我将其命名为NumberExt.kt。因此,我并不是要将这些代码放在您的活动类中。如果您将它们放在单独的文件中,那么这些代码将在整个项目中都可用。无论如何,如果您真的想要创建一个类,也没有问题,我可以帮您实现。 - aminography
1
使用这些扩展非常容易。因此,只需在双数后面加上 .,IntelliJ 就应该通过按下 alt+enter 来建议 vulgarFraction。请参见:https://imgur.com/eO5ScaQ - aminography
1
如果没有成功,请尝试这个链接:https://hastebin.com/tumuvapura.kotlin。使用它只需调用函数:`NumberUtils.vulgarFraction(3.14)`。 - aminography
1
是的,点号表示法应该可以工作,但出于某种原因它没有……我一定在哪里做错了。一旦我从活动中删除了分数代码,它就会抛出错误,我再也无法从我放置它的 .Kt 文件中访问 .vulgarFraction。我将使用您制作的对象版本,她是一件艺术品。这解决了问题,再次感谢 aminography! - RobbB
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接