微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

小数到低俗分数,Kotlin Android NumberExt.kt 测试说明

如何解决小数到低俗分数,Kotlin Android NumberExt.kt 测试说明

我一直在尝试将Swift方法转换为Kotlin,但在这里没有得到任何帮助: Decimal to vulgar fraction conversion method- need help converting from Swift to 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))
        }
    }
}

解决方法

通常,我倾向于在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
Number:39.275953137210614,Vulgar: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
Number:28.639946409572655,Vulgar:28⅝,Rounded: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()

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。