我正在构建板球应用程序。我希望数字增加.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)
答案 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的范围,此答案也适用于负值。