2011-08-28 132 views
3

我想就一些建议如何优化while循环如下:浮点比较

double minor_interval = 0.1; 
double major_interval = 1.0; 

double start   = 0.0; 
double finish   = 10.0; 

printf("Start\r\n"); 

while (start < finish) 
{ 
    printf("Minor interval: %.20f\r\n", start); 

    double m = fmod(start, major_interval); 
    printf("m: %.20f\r\n", m); 

    if (m == 0) 
     printf("At major interval: %.20f\r\n", start); 

    start += minor_interval; 
} 

printf("Finished\r\n"); 

从本质上讲,我在环由微小的间隔递增计数器,想如果我处于主要区间,则每次都知道循环。把它画成毫米间隔的标尺,每当我到一个主要的间隔时,我想画一厘米。鉴于浮点运算的不准确性,我如何修改上述循环来实现我需要的功能?我尝试了使用容差比较模数结果的不同方法,但没有运气。请注意,次要间隔和主要间隔可以是任何值,即小数= 0.4和大数= 1.6(以画四分之一英里增量)。

在此先感谢。

+0

如果您的号码是唯一正确的,以2小数点,你为什么不乘以100的所有号码,去了很精确的整数算术? 对于整数,[div](http://www.cplusplus.com/reference/clibrary/cstdlib/div/)或[ldiv](http://www.cplusplus.com/reference/clibrary/cstdlib/ldiv/ )。 –

+0

@Ron英寸秤通常会有1/8或0.125的增量。为什么在解决不完美的解决方案时很容易避免像你所建议的那样限制。 –

+0

@大卫我避免了浮点运算,除非无法避免,或者在整数运算中实现效率很高。我只是建议数字是否限制在2位小数,但如果情况并非如此,我肯定会选择你的解决方案(我把你的答案投给了:))。 –

回答

6

我会用一个for循环来实现这个变量int变量i。使用整数避免了由于浮点运算的限制而导致的舍入问题。 [见What Every Computer Scientist Should Know About Floating-Point Arithmetic。]

让从0i运行到iFinish-1并设置time等于start + i*minor_intervaliFinish的值可以通过将(finish-start)/minor_interval四舍五入到最近的整数来找到。

主轴更新可以用类似的方式处理。回合major_interval/minor_interval至最近的int,比如k。然后在每次第k次迭代中更新主轴标记。

在代码方面,它看起来是这样的:

double round(double r) { 
    return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5); 
} 
... 
int iFinish = round((finish-start)/minor_interval); 
int k = round(major_interval/minor_interval); 
for (int i=0; i<iFinish; i++) 
{ 
    double time = start + i*minor_interval; 
    bool isMajor = (i%k == 0); 
    ... 
} 
0

为什么你的宽容的方法不起作用的原因是,它只占时保存的值略高于它应该是。 (例如,当它是1.0001,而不是1,如果是0.999,而不是1,你的方法是行不通的)

为了解决这个问题,检查它是否在预期值的侧的公差范围内。

因此,而不是:

if (m == 0) 

使用:

if (m < small_value || major_interval - m < small_value) 

其中small_value是一样的东西1E-8。

0

我会让循环成为使用整数的for循环。另外,由于这些tyes数字的不稳定性质,您应该避免使用==运算符。

所以对双打转换成整数的循环的目的:

numIntervals = (int)((finish - start)/minor_intervals); 
majIntervalsGap = numIntervals/(int)((finish - start)/major_intervals); 
double time = start; 
for (int loop = 0;; loop < numIntervals; ++loop) 
{ 
    bool isMajor = ((loop % majIntervalsGap) == 0); 

    ... do you ourput here as you have the desired info for it 
    time += minor_interval; 
} 
+0

(int)演员如何处理四舍五入?我相当肯定,它不会绕到最近,这是这里所需要的。 –