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

温度单位转换App输入超4位数字结果异常的解决求助

问题分析与解决方案

问题根源

你的代码依赖Double类型处理温度数值,但Double作为浮点数,存在精度上限(有效位数约15-17位),当输入数字长度超过一定范围时,Double无法精确存储该数值,直接导致后续转换计算出现偏差。同时,你手动用times(100000.0).roundToInt().div(100000.0)处理小数的逻辑,也会额外引入精度损失。

修复方案

改用BigDecimal处理所有数值计算与转换——它支持任意精度的十进制数,能彻底规避浮点数精度问题,同时完美支持超长数字输入。以下是修改后的完整代码:

修改后的代码

import java.math.BigDecimal
import java.math.RoundingMode

@Composable
fun TemperatureScreen(
    conversionModel: ConversionModel,
    navController: NavHostController
) {
    val focusRequester = remember { FocusRequester() }
    var number by rememberSaveable { mutableStateOf("1") }
    var sourceUnit by remember { mutableStateOf(TemperatureUnits.Kelvin) }
    var targetUnit by remember { mutableStateOf(TemperatureUnits.DegreeCelsius) }
    var expandedSU by remember { mutableStateOf(false) }
    var expandedTU by remember { mutableStateOf(false) }

    // 用BigDecimal安全转换输入字符串,避免非法输入崩溃
    val inputValue = runCatching { BigDecimal(number) }.getOrNull()
    // 基于BigDecimal完成温度转换
    val convertedValue = inputValue?.let { convertTemperatureValueTo(it, sourceUnit, targetUnit) }
    // 保留5位小数并转为普通字符串(避免科学计数法)
    val roundedValue = convertedValue?.setScale(5, RoundingMode.HALF_UP)?.toPlainString()

    // 此处保留你原有的UI实现代码(你提供的片段中未包含,故省略)
}

// 所有转换函数改用BigDecimal作为参数和返回值
fun convertTemperatureValueTo(
    value: BigDecimal,
    sourceUnit: TemperatureUnits,
    targetUnit: TemperatureUnits
): BigDecimal {
    return when (sourceUnit) {
        TemperatureUnits.Kelvin -> when (targetUnit) {
            TemperatureUnits.Kelvin -> value
            TemperatureUnits.DegreeCelsius -> kelvinToCelsius(value)
            TemperatureUnits.Fahrenheit -> kelvinToFahrenheit(value)
            TemperatureUnits.Rankine -> kelvinToRankine(value)
        }
        TemperatureUnits.DegreeCelsius -> when (targetUnit) {
            TemperatureUnits.Kelvin -> celsiusToKelvin(value)
            TemperatureUnits.DegreeCelsius -> value
            TemperatureUnits.Fahrenheit -> celsiusToFahrenheit(value)
            TemperatureUnits.Rankine -> celsiusToRankine(value)
        }
        TemperatureUnits.Fahrenheit -> when (targetUnit) {
            TemperatureUnits.Kelvin -> fahrenheitToKelvin(value)
            TemperatureUnits.DegreeCelsius -> fahrenheitToCelsius(value)
            TemperatureUnits.Fahrenheit -> value
            TemperatureUnits.Rankine -> fahrenheitToRankine(value)
        }
        TemperatureUnits.Rankine -> when (targetUnit) {
            TemperatureUnits.Kelvin -> rankineToKelvin(value)
            TemperatureUnits.DegreeCelsius -> rankineToCelsius(value)
            TemperatureUnits.Fahrenheit -> rankineToFahrenheit(value)
            TemperatureUnits.Rankine -> value
        }
    }
}

//---------------------------------Kelvin To Any--------------------------------------------------------------------
fun kelvinToCelsius(kelvin: BigDecimal): BigDecimal {
    return kelvin.subtract(BigDecimal("273.15"))
}

fun kelvinToFahrenheit(kelvin: BigDecimal): BigDecimal {
    return kelvin.subtract(BigDecimal("273.15"))
        .multiply(BigDecimal("9").divide(BigDecimal("5"), 10, RoundingMode.HALF_UP))
        .add(BigDecimal("32"))
}

fun kelvinToRankine(kelvin: BigDecimal): BigDecimal {
    return kelvin.multiply(BigDecimal("1.8"))
}

//---------------------------------Celsius To Any--------------------------------------------------------------------
fun celsiusToKelvin(celsius: BigDecimal): BigDecimal {
    return celsius.add(BigDecimal("273.15"))
}

fun celsiusToFahrenheit(celsius: BigDecimal): BigDecimal {
    return celsius.multiply(BigDecimal("9").divide(BigDecimal("5"), 10, RoundingMode.HALF_UP))
        .add(BigDecimal("32"))
}

fun celsiusToRankine(celsius: BigDecimal): BigDecimal {
    val kelvin = celsius.add(BigDecimal("273.15"))
    return kelvin.multiply(BigDecimal("1.8"))
}

//---------------------------------fahrenheit To Any--------------------------------------------------------------------
fun fahrenheitToKelvin(fahrenheit: BigDecimal): BigDecimal {
    return fahrenheit.subtract(BigDecimal("32"))
        .multiply(BigDecimal("5").divide(BigDecimal("9"), 10, RoundingMode.HALF_UP))
        .add(BigDecimal("273.15"))
}

fun fahrenheitToCelsius(fahrenheit: BigDecimal): BigDecimal {
    return fahrenheit.subtract(BigDecimal("32"))
        .multiply(BigDecimal("5").divide(BigDecimal("9"), 10, RoundingMode.HALF_UP))
}

fun fahrenheitToRankine(fahrenheit: BigDecimal): BigDecimal {
    return fahrenheit.add(BigDecimal("459.67"))
}

//---------------------------------rankine To Any--------------------------------------------------------------------
fun rankineToKelvin(rankine: BigDecimal): BigDecimal {
    return rankine.multiply(BigDecimal("5").divide(BigDecimal("9"), 10, RoundingMode.HALF_UP))
}

fun rankineToCelsius(rankine: BigDecimal): BigDecimal {
    return rankine.subtract(BigDecimal("491.67"))
        .multiply(BigDecimal("5").divide(BigDecimal("9"), 10, RoundingMode.HALF_UP))
}

fun rankineToFahrenheit(rankine: BigDecimal): BigDecimal {
    return rankine.subtract(BigDecimal("459.67"))
}

// 适配你的TemperatureUnits枚举(若枚举结构不同可自行调整)
enum class TemperatureUnits {
    Kelvin, DegreeCelsius, Fahrenheit, Rankine
}

关键修改说明

  • 全链路用BigDecimal替代Double:从输入转换到计算输出全程使用BigDecimal,彻底解决浮点数精度丢失问题,支持任意长度的数字输入。
  • 精确的除法运算:涉及9/5、5/9这类非整数除法时,指定足够的计算精度(示例中设为10位)和舍入模式(RoundingMode.HALF_UP),保证计算结果准确。
  • 简化结果处理:用setScale(5, RoundingMode.HALF_UP)直接控制小数位数,toPlainString()自动避免科学计数法,无需额外处理逻辑。
  • 安全的输入转换:通过runCatching捕获非法输入的转换异常,避免App崩溃。

额外优化建议

  • 给TextField添加输入过滤器,限制仅能输入数字和小数点,减少非法输入场景。
  • 可新增自定义小数位数的设置项,让用户按需调整显示精度。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 13:30:59