Objective c 从范围计算四舍五入值的最佳算法
我在画一些图表,横轴上有时间,纵轴上有价格 价格可能在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中的算法。谢谢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个有效水平。
-(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的增加每月增加一次。你是不是也在努力工作?在这种情况下,您需要调整代码第二部分中的常量。