You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin实现厘米与英尺英寸互转的精度问题求助

厘米与英尺/英寸互转的循环精度偏差问题

我正在实现用户身高在厘米(cm)与英尺(ft)、英寸(inc)之间的互转功能,遇到了循环转换的精度偏差问题:

  • 输入100cm,点击英尺转换按钮得到3ft3inc;
  • 不修改内容点击厘米转换按钮,3ft3inc会被转换为99cm;
  • 再次点击英尺转换按钮,又得到3ft2inc,如此循环偏差。

下面是我的View和ViewModel代码,求排查问题:

View代码

Button(
    modifier = Modifier.padding(5.dp),
    colors = ButtonDefaults.buttonColors(backgroundColor = toggleButtonBackgroundColor1),
    shape = RoundedCornerShape(25.dp),
    elevation = ButtonDefaults.elevation(0.dp, 0.dp),
    onClick = {
        if(!btnHeightIsSelected){
            btnHeightIsSelected = true
            btnFtIsSelected = false
            isClickIn = false
            isClickFt = false
         
            onFtToCmChange(state.ft.toInt(),state.inc.toInt())
        }

    }) {
    Text(
        text = stringResource(id = R.string.cm),
        color = toggleButtonTextColor1
    )
}


Button(
    modifier = Modifier
        .padding(5.dp),
    colors = ButtonDefaults.buttonColors(backgroundColor = toggleButtonBackgroundColor2),
    shape = RoundedCornerShape(25.dp),
    elevation = ButtonDefaults.elevation(0.dp, 0.dp),
    onClick = {
        if(!btnFtIsSelected){
            btnFtIsSelected = true
            btnHeightIsSelected = false
            onCmToFtChange(state._height)
        }

    }) {
    Text(
        text = stringResource(id = R.string.ft_in),
        color = toggleButtonTextColor2
    )
}


if (btnFtIsSelected) {
    CustomHeightScreenIncInputField(
        ftValue = state.ft,
        incValue = state.inc,
        ftPlaceholder = "ft",
        inPlaceholder = "in",
        onClickFt = {
            onPickerStateChanged(HeightPickerState.FT)
            isClickIn = false
            isClickFt = true
        },
        onClickIn = {
            onPickerStateChanged(HeightPickerState.IN)
            isClickFt = false
            isClickIn = true
        }
    )
} else {
    CustomInputField(
        isFocused = inputFocused,
        placeholder = "your height (cm)",
        currentValue = state._height.toString(),
        onClick = {
            onPickerStateChanged(HeightPickerState.HEIGHT)
        })
}

ViewModel代码

fun onFtToCmChange(ft: Int,inc:Int) {

    //val cmHeight = (ft*12 + inc) * 2.54
    val totalInches = ft * 12 + inc
    val cmHeight = totalInches * 2.54

    _viewState.update {
        it.copy(
            _height = cmHeight.toInt(),
            ft = ft.toString(),
            inc = inc.toString(),
            height = "${cmHeight.roundToInt()}"
        )
    }
}



fun onCmToFtChange(_height: Int) {

    val totalInches = _height / 2.54
    val ft = (totalInches / 12).toInt()
    val inc = (totalInches % 12).toInt()

 
    _viewState.update {
        it.copy(
            ftHeight = "$ft.$inc".toDouble(),
            height ="$_height",
            ft = ft.toString(),
           
            inc = inc.toString()
        )
    }
}

问题分析

精度偏差的核心原因是整数截断和浮点运算的舍入误差:

  1. 厘米转英尺/英寸时,_height / 2.54得到的浮点值直接用toInt()截断小数部分,而非四舍五入。比如100cm转英寸约为39.37,截断后是39英寸,对应3ft3inc;
  2. 英尺/英寸转回厘米时,39*2.54=99.06cm,用cmHeight.toInt()直接截断成99cm,而非四舍五入到100cm;
  3. 循环转换时,每次截断都会丢失精度,导致数值持续偏差。

解决方案

1. 转换时统一使用四舍五入

修改ViewModel中的两个转换函数,替换截断逻辑为四舍五入:

修改onFtToCmChange:

fun onFtToCmChange(ft: Int, inc: Int) {
    val totalInches = ft * 12 + inc
    val cmHeight = totalInches * 2.54
    val roundedCm = cmHeight.roundToInt()

    _viewState.update {
        it.copy(
            _height = roundedCm,
            ft = ft.toString(),
            inc = inc.toString(),
            height = roundedCm.toString()
        )
    }
}

修改onCmToFtChange:

fun onCmToFtChange(_height: Int) {
    val totalInches = (_height / 2.54).roundToInt() // 四舍五入到最近整数英寸
    val ft = totalInches / 12
    val inc = totalInches % 12

    _viewState.update {
        it.copy(
            ftHeight = "$ft.$inc".toDouble(),
            height = _height.toString(),
            ft = ft.toString(),
            inc = inc.toString()
        )
    }
}

2. 可选:优化精度存储(进阶)

如果需要更高精度,可以在ViewModel中用浮点类型存储原始值(比如厘米用Double),仅在UI显示时做格式化。但对于身高的日常使用场景,四舍五入到整数英寸和厘米已经足够。


内容的提问来源于stack exchange,提问作者NewPartizal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 11:05:17