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() ) } }
问题分析
精度偏差的核心原因是整数截断和浮点运算的舍入误差:
- 厘米转英尺/英寸时,
_height / 2.54得到的浮点值直接用toInt()截断小数部分,而非四舍五入。比如100cm转英寸约为39.37,截断后是39英寸,对应3ft3inc; - 英尺/英寸转回厘米时,39*2.54=99.06cm,用
cmHeight.toInt()直接截断成99cm,而非四舍五入到100cm; - 循环转换时,每次截断都会丢失精度,导致数值持续偏差。
解决方案
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
相关产品推荐
相关产品推荐

