如何检查浮点数是否是Swift中另一个浮点数的倍数

时间:2015-05-25 17:04:01

标签: ios swift

我从用户那里收到一个浮点数,并根据定义的增量(0.1,0.5,0.01等)检查它是否有效。例如,如果增量为0.5,则1.0,1.5,2.0有效但1.2不有效。我正在使用modulo检查它是否有效。

if (input % increment) == 0 {
    println("Pass")
} else {
    println("Fail")
}

问题是当增量为0.1时,输入的大多数有效值都被检测为无效。

我使用了this answer中给出的公式,它改进了有效输入的检测,但大部分时间仍然失败。

4 个答案:

答案 0 :(得分:4)

你的问题是0.1在二进制中不能完全表示,而例如0.5。这意味着0.1 * 5不等于0.5。这很像十进制,其中(1/3)*3≃0.3333333* 3 = 0.99999999不是1.要解决这类问题,你可以引入一个epsilon。 epsilon是一个非常小的值,你可以检查你的结果是否与你想要的值只有很小的距离,如果你希望这个值是正确的。

答案 1 :(得分:3)

要处理小数点后面有一个数字的数字:

if (input * 10) % (increment * 10) == 0 {
    println("Pass")
} else {
    println("Fail")
}

要在小数点后处理多个数字的数字,只需增加倍数即可。例如,if (input * 100000) % (increment * 100000) == 0

答案 2 :(得分:3)

基于James Snook's answer,我最终得到了这个解决方案。

let epsilon = 1e-6
let division = input / increment
let diff = abs(division - round(division))
if (diff < epsilon) {
    println("Pass")
} else {
    println("Fail")
}

答案 3 :(得分:2)

我相信模数只适用于整数,如果我是对的,你应该自己做一个解决方法,看看给定的数字是否为多数,转换为:除法的结果必须是整数。 代码应该是这样的:

let floatDivision = input/increment;
let isInteger = floor(floatDivision) == floatDivision // true
if (isInteger) {
    println("Pass")
} else {
    println("Fail")
}

这应该适用于任何增量编号(甚至超过一个小数点)。

修改

作为詹姆斯赛义德,1.2超过0.1的浮点除法并不完全编码为12而是11.9999 ...所以我在比较中添加了epsilon:

let input = 1.2; 
let increment = 0.1; 
let epsilon = 0.00000000000001;

let floatDivision = input/increment;
let dif = abs(round(floatDivision) - floatDivision);

println(String(format: "%.20f", floatDivision)); // 11.99999999999999822364  
println(String(format: "%.20f", round(floatDivision))); // 12.00000000000000000000  
println(String(format: "%.20f", dif)) // 0.00000000000000177636

let isInteger = dif < epsilon // Pass if (isInteger) {
    println("Pass") } else {
    println("Fail") }

祝你好运。