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

时间:2018-12-16 14:45:13

标签: ios swift int uistepper

我正在构建板球应用程序。我希望数字增加.1,但一旦达到.5,然后再按一次plus,我希望将其舍入为整个值。

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

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

每当它达到数字的.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)

enter image description here

2 个答案:

答案 0 :(得分:4)

浮点数为troublesome。实际上,您绝对不应测试浮点数是否与另一个值相等。在您的情况下,0.1不能用浮点数精确表示,因此增加0.1会导致误差增加。因此,当您期望使用0.499999999时,您的电话号码可能以0.5结尾。

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

要从88.5跳到89.0(递增),以及从89.0跳到88.5(递减),请检查数字是6还是{{ 1}},然后按9递增/递减步进值:

4

通过步进完整的值,不会引入错误。

答案 1 :(得分:0)

如果步数从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在这里起着数字验证器的作用。 UIStepper值可以通过MyFloat对象进行纠正。

下一个问题是浮点数可以通过精确控制方式进行比较。换句话说,浮点数的精度可以通过限制数字与实际数字之间不同的ab来实现,例如abs(ab)

基于此假设,构造一个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的范围,此答案也适用于负值。