Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 从范围计算四舍五入值的最佳算法_Objective C_Algorithm - Fatal编程技术网

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

Objective c 从范围计算四舍五入值的最佳算法,objective-c,algorithm,Objective C,Algorithm,我在画一些图表,横轴上有时间,纵轴上有价格 价格可能在0.23487至0.8746或20.47至45.48或1.4578至1.6859或9000至12000之间。。。你知道,任何范围都有可能。数字的精度也可能不同(但通常是小数点后2位或4位) 现在在垂直轴上,我需要显示价格,但不是所有价格,只是一些重要的水平。我需要显示尽可能多的重要级别,但这些级别之间的距离不应超过30像素( 因此,如果我有一个图表,其数据的价格范围为1.4567到1.6789,图表高度为500,我可以显示最多16个有效水平。

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

价格可能在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…等等。所以我想根据我有多少空间来显示尽可能多的重要级别,但总是只在一些重要值(我不是说四舍五入值也是重要的)显示级别,它们是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中的算法。谢谢

-(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;
}
-(浮点)getPriceLineDenominator
{
NSArray*possVal=[NSArray阵列及其对象:
[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],
零];
float diff=最高价格最低价格;//显示值的范围
双乘数=1;
如果(diff=30)//30是所示价格水平之间的最小距离
{
结果=f;
打破
}
}
返回结果;
}

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

假设您知道数据中的最小值和最大值。您还知道需要多少级别

最大值和最小值之间的差值除以级别数(稍微)小于每个子范围的大小

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);
double diff=最高价格-最低价格;//显示值的范围
双范围=差异/级别;//范围大小
双对数范围=对数10(范围);//对数10
int lograngint=(int)logrange;//整数部分
double lograngerest=logrange-lograngeint;//小数部分
如果(lograngest<0){//如果为负,则调整
lograngerest+=1;
lograngeint-=1;
}
/*现在,您可以将lograngerest增加到您喜欢的边界*/
如果(lograngerest

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

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

int maxDivs = height / closest;
将范围划分为这么多个分区。您很可能会得到一些难看的值,但它提供了一个起点:

double minTickSpacing = diff/maxDivs;
您需要从该间距开始递增,直到达到一个适当数量级的“有效”值。您可以使用一些数学函数来查找顺序,而不是循环和除/乘:

double multiplier = pow(10, -floor(log10(minTickSpacing)));
{2,2.5,5,10}
范围中选择下一个空格——为了简单起见,我将使用常量和
if
-
else
来执行此操作:

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;
double scaledSpacing=乘数*mintickspacking;
如果(缩放间距<2)结果=2;
否则,如果(缩放间距<2.5)结果=2.5;
否则,如果(缩放间距<5)结果=5;
其他结果=10;
返回结果/乘数;

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

我认为我不理解
重要的
值部分。你想如何确定
重要的
意味着什么我需要的ficant是四舍五入到1,0.5,0.25,0.2,0.1.或10,5,2.5,2,1或100,50,25,20,10或0.1,0.05,0.0025,0.001或0.001,0.0005,0.00025,0.0002,0.0001等。这取决于图表中显示的数字以及我有多少空间。感谢walkytalky。这与pmg的解决方案不一样或非常相似吗?我将他的帖子标记为n回答因为他是第一个(除非你的解决方案不同)。@Michal他们非常相似,是的。我也会接受pmg的:)这里有些混乱-“lograngerest”永远不会是负的,假设
(int)
意味着“强制转换为int”,“四舍五入为0”,等等。logx随着x的增加每月增加一次。你是不是也在努力工作?在这种情况下,您需要调整代码第二部分中的常量。