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

Swift保留X位小数舍入异常:0.99999舍入为1.00而非0.99

解决Swift中特定范围小数舍入的边界问题

你遇到的其实是标准四舍五入规则和自定义边界需求的冲突——0.99999按常规四舍五入到两位小数确实会得到1.00,但你希望在0~1的数值范围内,保留n位小数时,即使舍入后会触达1.00,也停留在该小数位数的最大值(比如两位的0.99),同时其他场景保持正常四舍五入(比如0.348→0.35)。

问题根源

你尝试的三种方法都是遵循标准四舍五入逻辑:0.99999 * 100 = 99.999,round(99.999)会得到100,最终结果自然是1.00。这完全符合数学上的四舍五入规则,但不符合你的特殊边界要求。

解决方案

我们可以在标准舍入的基础上,增加一个边界判断:如果原数小于1,但标准舍入后的结果等于1.0,就返回该小数位数下的最大值(即1.0 - 10^(-decimals)),否则返回正常舍入结果。

方法1:基于浮点运算的快速实现

适合精度要求不是极端严苛的场景:

func customRound(value: Double, decimals: Int) -> Double {
    guard decimals >= 0 else { return value }
    // 原数已是1或更大,直接返回1.0
    guard value < 1.0 else { return 1.0 }
    
    let divisor = pow(10.0, Double(decimals))
    var roundedVal = round(value * divisor) / divisor
    
    // 若舍入后触达1.0,替换为当前小数位的最大值
    if roundedVal == 1.0 {
        roundedVal = 1.0 - pow(10.0, -Double(decimals))
    }
    return roundedVal
}

// 测试案例
print(customRound(value: 0.99999, decimals: 2)) // 输出0.99
print(customRound(value: 0.348, decimals: 2))   // 输出0.35
print(customRound(value: 1.0, decimals: 2))     // 输出1.0

方法2:基于NSDecimalNumber的精确实现(推荐)

浮点运算可能存在精度误差(比如某些极接近1的数可能被误判),用NSDecimalNumber可以彻底避免这个问题:

import Foundation

func customRoundDecimal(value: Double, decimals: Int) -> NSDecimalNumber {
    guard decimals >= 0 else { return NSDecimalNumber(value: value) }
    let one = NSDecimalNumber(value: 1.0)
    let input = NSDecimalNumber(value: value)
    
    // 原数已是1或更大,直接返回1.0
    if input.compare(one) != .orderedAscending {
        return one
    }
    
    // 配置标准四舍五入规则
    let behavior = NSDecimalNumberHandler(
        roundingMode: .plain,
        scale: Int16(decimals),
        raiseOnExactness: false,
        raiseOnOverflow: false,
        raiseOnUnderflow: false,
        raiseOnDivideByZero: true
    )
    let roundedVal = input.rounding(accordingToBehavior: behavior)
    
    // 若舍入后等于1.0,替换为对应小数位的最大值
    if roundedVal.compare(one) == .orderedSame {
        let divisor = NSDecimalNumber(mantissa: 1, exponent: Int16(-decimals), isNegative: false)
        return one.subtracting(divisor)
    }
    
    return roundedVal
}

// 测试案例
print(customRoundDecimal(value: 0.99999, decimals: 2)) // 输出0.99
print(customRoundDecimal(value: 0.348, decimals: 2))   // 输出0.35
print(customRoundDecimal(value: 1.0, decimals: 2))     // 输出1

逻辑验证

这个方案的核心是:

  • 对绝大多数数值保持标准四舍五入,满足你0.348→0.35的需求
  • 仅当原数小于1,但标准舍入后会得到1.0时,强制将结果设为该小数位数的最大值,完美匹配你对0.99999的预期

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:30:12