Ios 如何检查带小数的双精度数是否可除?
我试图测试一个数字是否可以被另一个数字完全整除(没有余数)。如果将其与int进行比较,则其工作正常:Ios 如何检查带小数的双精度数是否可除?,ios,objective-c,math,floating-point,double,Ios,Objective C,Math,Floating Point,Double,我试图测试一个数字是否可以被另一个数字完全整除(没有余数)。如果将其与int进行比较,则其工作正常: NSTimeInterval timeElapsed = // a double goes here // round to 3 decimal points to avoid floating point weirdness timeElapsed = [[NSString stringWithFormat:@"%.3f",timeElapsed] doubleValue]; 然后 //
NSTimeInterval timeElapsed = // a double goes here
// round to 3 decimal points to avoid floating point weirdness
timeElapsed = [[NSString stringWithFormat:@"%.3f",timeElapsed] doubleValue];
然后
// This works correctly
if (fmod(timeElapsed, 1) == 0) {
NSLog(@"is divisible");
}
但如果我将其与十进制进行比较,它将失败,只是间歇性地触发:
// This does NOT work correctly
if (fmod(timeElapsed, .1) == 0) {
NSLog(@"is divisible");
}
我做错了什么
编辑:在阅读了下面的答案和精彩评论后,我得出结论,整个方法都是一个坏主意。无法保证能够生成特定的时间间隔。最好只创建单独的计时器,而不是只听一个“主”计时器。一般来说,浮点数不能精确表示,因为只能用有限的位数来表示它们(通常是32或64位)。因此,您不应测试精确的相等性,而应在可接受的小公差范围内进行测试,例如:
if (fabs(fmod(timeElapsed, .1)) < SOME_SMALL_VALUE) {
NSLog(@"is divisible");
}
if(fabs(fmod(timeappeased.1))
如果你要写任何严肃的数字代码,最好读一下。一般来说,浮点数不能精确表示,因为你只有有限的位数来表示它们(通常是32或64位)。因此,您不应测试精确的相等性,而应在可接受的小公差范围内进行测试,例如:
if (fabs(fmod(timeElapsed, .1)) < SOME_SMALL_VALUE) {
NSLog(@"is divisible");
}
if(fabs(fmod(timeappeased.1))
如果您要编写任何严肃的数字代码,最好阅读以下内容。如果您想在0.1秒后执行任务,请反复使用NSTimer:
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.1
target:self
selector:@selector(yourMethod:)
userInfo:nil
repeats:YES];
要停止计时器调用,请执行以下操作:
[timer invalidate];
如果要在0.1秒后重复使用NSTimer执行任务:
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.1
target:self
selector:@selector(yourMethod:)
userInfo:nil
repeats:YES];
要停止计时器调用,请执行以下操作:
[timer invalidate];
这是一个糟糕的方法。浮点数不可信。每个元素都有自己的计时器,这样你就不必听特定的数字了。这是一种糟糕的方法。浮点数不可信。为每个元素指定自己的计时器,这样您就不必听特定的数字。什么对您不起作用?@giorashc例如,如果
timepassed
为3.400,它应该通过测试,因为它应该可以被.1
完全整除。但事实并非如此。保罗·R在这个问题上有很好的观点。据我所知,你正试图每0.1秒做一件事?@giorashc是的,没错。什么对你不起作用?@giorashc如果,例如,timepassed
是3.400,它应该通过测试,因为它应该完全可以被.1
整除。但事实并非如此。保罗·R在这个问题上有很好的观点。据我所知,你正试图每0.1秒做一件事?@giorashc是的,没错。如果NSTimeInterval是一个浮点值,那么你是否舍入它并不重要。如果浮点值太复杂,你可以将两个值都乘以1000,舍入为一个整数,并使用mod获得小数点后3位的精度。打印到更多的小数点。尽管在我看来,马库斯的建议更好,原因有几个,因为mod操作可能很容易出现“错误的一面”(因此它可能非常接近于零,而不是非常接近于除数)。是 啊乘法,转换为int,然后转换为mod。您看到的并不总是您得到的:)因为fmod
被定义为返回一个与第一个参数具有相同符号的值,所以fabs
是浪费时间的。其次,没有指定一些较小的值,所以这个答案是不完整的。先前的一条评论建议使用FLT_EPSILON
,但一旦经过的时间超过2秒就会失败:数字2及以上的ULP大于FLT_EPSILON
,因此除了2.5和3等精确倍数外,所有接近.1倍数的数字的测试都将返回false,即使假设系统实际测量的时间粒度为FLT_EPSILON
。如果NSTimeInterval是一个浮点值,则不管是否舍入它。如果浮点值看起来太复杂,可以将两个值乘以1000,将它们舍入为一个整数,并使用mod获得小数点后3位的精度。打印到更多的小数点。尽管在我看来,马库斯的建议更好,原因有几个,因为mod操作可能很容易出现“错误的一面”(因此它可能非常接近于零,而不是非常接近于除数)。是 啊乘法,转换为int,然后转换为mod。您看到的并不总是您得到的:)因为fmod
被定义为返回一个与第一个参数具有相同符号的值,所以fabs
是浪费时间的。其次,没有指定一些较小的值,所以这个答案是不完整的。先前的一条评论建议使用FLT_EPSILON
,但一旦经过的时间超过2秒就会失败:数字2及以上的ULP大于FLT_EPSILON
,因此除了2.5和3等精确倍数外,所有接近.1倍数的数字的测试都将返回false,即使假设系统实际测量的时间粒度为FLT_EPSILON
.NSTimer可能是最好的方法,但有一个警告:如果计时器的触发时间发生在长调用期间或运行循环处于不监视计时器的模式下,直到下次运行循环检查计时器时,计时器才会启动。因此,计时器可能触发的实际时间可能是计划触发时间之后的一段重要时间。
您的当前方法也会遇到同样的问题。NSTimer可能是最佳方法,但需要注意,from:如果计时器的触发时间发生在长调用期间或运行循环处于非monit模式时