如何在递增 0.1 时将每个 .5 数字四舍五入为整数

How to round each .5 number up to whole value when incrementing by 0.1

我正在构建一个板球应用程序。我希望数字增加 .1,但一旦它达到 .5 并且我再次点击加号,我希望它四舍五入为整数。

例如。 2.1、2.2、2.3、2.4、2.5 然后跳转到 3.0(然后重新开始 3.1、3.2、3.3 等)

我的步进器目前上下移动 .1,但它包括小数(.6、.7、.8 和 .9)

每次它达到数字的 0.5 时,我都需要将其四舍五入。减法时相同。

这是我的代码:

var oversFloat: Float = 0.0

@IBOutlet weak var displayOversLabel: UILabel!
@IBAction func OversStepper(_ sender: UIStepper) {
    let oversValue = Float(sender.value)
    displayOversLabel.text = String(oversValue)

浮点数是troublesome。你真的不应该测试一个浮点数与另一个值是否相等。在您的情况下 0.1 不能用浮点数精确表示,因此增加 0.1 会导致错误增加。因此,当您期望 0.5.

时,您的号码可能会以 0.499999999 结尾

对于您的情况,您可以通过在步进器中使用整数来轻松避免此问题。将步进器修改为 1 而不是 0.1,并将最小值和最大值乘以 10。然后,当您使用步进器值更新标签时,将步进器值除以 10

88.5跳到89.0是递增的,从89.0跳到88.5是递减的,检查个位是6还是9 然后 increment/decrement 您的步进值 4:

@IBAction func oversStepper(_ sender: UIStepper) {
    let value = Int(sender.value)
    let remainder = value % 10
    if remainder == 6 {
        sender.value = Double(value + 4)
    } else if remainder == 9 {
        sender.value = Double(value - 4)
    }
    displayOversLabel.text = String(format: "%.1f", sender.value / 10)
}

步进整数值,不会引入错误。

如果步数从 0.1 更改为 0.01 或 0.001,我会为您的请求添加一个通用答案。

第一个是为了简化案例,这样@IBAction可以被调用而不会混淆。

      @IBAction func oversStepper(_ sender: UIStepper) {
        let myValue : MyFloat = MyFloat(Float(sender.value))
        sender.value = myValue.value

        displayOversLabel.text = String(format: "%.1f", sender.value)
    }

MyFloat 在这里扮演了一个数字验证器的角色。可以通过 MyFloat 对象更正 UIStepper 值。

下一个问题是Float可以通过精度控制的方式进行比较。换句话说,Float数的精度可以通过限制一个数和实际数的abs差来实现,比如abs(a-b) < precision(1e-4),所以我们知道它们足够接近了。

基于这个假设,构造一个MyFloat和运行 testCases如下:

    let presicion: Float = 1e-4

    struct MyFloat {
        private var val: Float = 0
        init(_ v: Float){value = v}
        var value : Float {
            get{ return val}
            set{
                 let ro = newValue.rounded()
                 let ground = newValue.rounded(FloatingPointRoundingRule.towardZero)
                 val = (trunc(newValue) == round(newValue) || abs((ground + ro) / 2.0 - newValue) < presicion ) ? newValue :
                 (abs(val - ro) < presicion) ? (ground + ro) / 2.0 : ro
            }
        }
        static   func +=(left: inout MyFloat, right: Float){
            left.value = left.value + right
        }
        static   func -=(left: inout MyFloat, right: Float){
            left.value = left.value - right
        }
    }


    //naive testCases
    var myFloat = MyFloat(10.0)
    myFloat += 0.1; assert(abs( myFloat.value - 10.1) < presicion);
    myFloat += 0.1; assert(abs( myFloat.value - 10.2) < presicion);
    myFloat += 0.1; assert(abs( myFloat.value - 10.3) < presicion);
    myFloat += 0.1; assert(abs( myFloat.value - 10.4) < presicion);
    myFloat += 0.1; assert(abs( myFloat.value - 10.5) < presicion);
    myFloat += 0.1; assert(abs( myFloat.value - 11.0) < presicion);
    myFloat += 0.1; assert(abs( myFloat.value - 11.1) < presicion);
    myFloat += 0.1; assert(abs( myFloat.value - 11.2) < presicion);
    myFloat += 0.1; assert(abs( myFloat.value - 11.3) < presicion);
    myFloat += 0.1; assert(abs( myFloat.value - 11.4) < presicion);
    myFloat += 0.1; assert(abs( myFloat.value - 11.5) < presicion);
    myFloat += 0.1; assert(abs( myFloat.value - 12.0) < presicion);
    myFloat += 0.1; assert(abs( myFloat.value - 12.1) < presicion);
    myFloat += 0.1; assert(abs( myFloat.value - 12.2) < presicion);
    myFloat -= 0.1; assert(abs( myFloat.value - 12.1) < presicion);
    myFloat -= 0.1; assert(abs( myFloat.value - 12.0) < presicion);
    myFloat -= 0.1; assert(abs( myFloat.value - 11.5) < presicion);
    myFloat -= 0.1; assert(abs( myFloat.value - 11.4) < presicion);
    myFloat -= 0.1; assert(abs( myFloat.value - 11.3) < presicion);
    myFloat -= 0.1; assert(abs( myFloat.value - 11.2) < presicion);
    myFloat -= 0.1; assert(abs( myFloat.value - 11.1) < presicion);
    myFloat -= 0.1; assert(abs( myFloat.value - 11.0) < presicion);
    myFloat -= 0.1; assert(abs( myFloat.value - 10.5) < presicion);
    myFloat -= 0.1; assert(abs( myFloat.value - 10.4) < presicion);
    myFloat -= 0.1; assert(abs( myFloat.value - 10.3) < presicion);
    myFloat -= 0.1; assert(abs( myFloat.value - 10.2) < presicion);

这种方法的优点是步长值可以更精确到0.001,无需任何新代码,只有一个参数需要注意:精度。 (例如,precision = 1e-6 在这种情况下会给出错误的答案。)

顺便说一句,这个答案也适用于通过屏蔽 (-1 + n,-0.5 + n) 范围的负值,n<=0.