首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从范围计算四舍五入值的最佳算法

从范围计算四舍五入值的最佳算法
EN

Stack Overflow用户
提问于 2011-07-05 04:14:10
回答 2查看 594关注 0票数 4

我在画一些图表,横轴上有时间,纵轴上有价格。

价格可以从0.23487到0.8746或20.47%到45.48%或1.4578到1.6859或9000到12000……你明白了吧,任何范围都可能在那里。数字的精度也可能不同(但通常是2位小数或4位小数)。

现在,在纵轴上,我需要显示价格,但不是所有的价格,只显示一些重要的水平。我需要显示尽可能多的重要级别,但这些级别彼此之间的距离不应超过30像素(。

因此,如果我有一个包含数据的图表,其价格范围从1.4567到1.6789,图表高度为500时,我可以显示最多16个显着水平。可见价格范围为1.6789-1.4567=0.2222。0.2222/16=0.0138,所以我可以显示级别1.4716,1.4854等等。但是我想将这个级别舍入到一些重要的数字,例如1.4600,1.4700,1.4800……或者1.4580,1.4590,1.4600..。或者1.4580,1.4585..。因此,我希望总是根据我有多少空间来显示尽可能多的显着性级别,但始终只显示一些有意义的值(我不是说舍入值,因为20.25也是重要的),它们是1、2、2.5、5和10或它们的乘数(10、20、25……或100、200、250...)或者他们的除法(0.1,0.2,0.25...或0.0001、0.0002、0.00025...)

我让它工作了,但我一点也不喜欢我的算法,它太长了,也不优雅。我希望有人能提出一些更优雅和通用的方式。我正在寻找算法,我可以实现不必要的代码。下面是我目前在objective-c中的算法。谢谢。

代码语言:javascript
复制
-(float) getPriceLineDenominator
{
    NSArray *possVal = [NSArray arrayWithObjects:
                        [NSNumber numberWithFloat:1.0],
                        [NSNumber numberWithFloat:2.0],
                        [NSNumber numberWithFloat:2.5],
                        [NSNumber numberWithFloat:5.0],
                        [NSNumber numberWithFloat:10.0],
                        [NSNumber numberWithFloat:20.0],
                        [NSNumber numberWithFloat:25.0],
                        [NSNumber numberWithFloat:50.0],
                        [NSNumber numberWithFloat:100.0],
                        nil];

    float diff = highestPrice-lowestPrice;//range of shown values

    double multiplier = 1;
    if(diff<10)
    {
        while (diff<10) 
        {
            multiplier/=10;
            diff = diff*10;
        }
    }
    else
    {
        while (diff>100) 
        {
            multiplier*=10;
            diff = diff/10;
        }
    }

    float result = 0;
    for(NSNumber *n in possVal)
    {
        float f = [n floatValue]*multiplier;
        float x = [self priceY:highestPrice];
        float y = [self priceY:highestPrice-f];
        if((y-x)>=30)//30 is minimum distance between price levels shown
        {
            result = f;
            break;
        }
    }
    return result;
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-07-05 06:18:19

您可以使用对数来标识每个子范围的大小。

假设您知道数据中的最小值和最大值。你也知道你想要多少个级别。

最大值和最小值之间的差除以层数(略)小于每个子范围的大小

代码语言:javascript
复制
double diff = highestPrice - lowestPrice;     // range of shown values
double range = diff / levels;                 // size of range
double logrange = log10(range);               // log10
int lograngeint = (int)logrange;              // integer part
double lograngerest = logrange - lograngeint; // fractional part
if (lograngerest < 0) {                       // adjust if negative
    lograngerest += 1;
    lograngeint -= 1;
}

/* now you can increase lograngerest to the boundaries you like */
if (lograngerest < log10(2)) lograngerest = log10(2);
else if (lograngerest < log10(2.5)) lograngerest = log10(2.5);
else if (lograngerest < log10(5)) lograngerest = log10(5);
else lograngerest = /* log10(10) */ 1;

/* and the size of each range is therefore */
return pow(10, lograngeint + lograngerest);

第一个范围在数据中的最小值之前一点开始。使用fmod查找之前的确切数量。

票数 3
EN

Stack Overflow用户

发布于 2011-07-05 06:34:10

正如您所说,可用高度决定了最大分段数。为了便于讨论,让我们避免使用幻数,假设您有可用的height像素和最小间距closest

代码语言:javascript
复制
int maxDivs = height / closest;

将范围划分为以下多个部分。你很可能会得到一些丑陋的值,但它提供了一个起点:

代码语言:javascript
复制
double minTickSpacing = diff/maxDivs;

你需要从这个间隔开始,直到你以适当的数量级达到你的一个“有意义的”值。您可以使用一些数学函数来查找顺序,而不是循环和除/乘:

代码语言:javascript
复制
double multiplier = pow(10, -floor(log10(minTickSpacing)));

从您的{2, 2.5, 5, 10}范围中选取下一个间距--为简单起见,我将使用常量和if-else

代码语言:javascript
复制
double scaledSpacing = multiplier * minTickSpacing;
if ( scaledSpacing < 2 ) result = 2;
else if ( scaledSpacing < 2.5 ) result = 2.5;
else if ( scaledSpacing < 5 ) result = 5;
else result = 10;

return result/multiplier;

或者类似的东西。完全未经测试,所以你需要检查标志和范围等等。而且肯定会有一些有趣的边缘情况。但我认为它应该在正确的范围内...

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6575708

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档