我正在编写一个应用程序,需要将标签舍入到最近的'nice'数字。我将在下面放一些代码来证明这一点,但我的问题是我使用了一系列其他ifs来找到这个数字,但我不能确定上限,所以这不是一个好的策略。有没有可以帮助我的已知算法或资源?
if (diff <= 1) {
roundAmount = 0.2;
} else if (diff <= 5) {
roundAmount = 1;
} else if (diff <= 10) {
roundAmount = 2;
} else if (diff <= 25) {
roundAmount = 5;
} else if (diff <= 50) {
roundAmount = 10;
} else if (diff <= 100) {
roundAmount = 20;
} else if (diff <= 250) {
roundAmount = 50;
} else if (diff <= 500) {
roundAmount = 100;
} else if (diff <= 1000){
roundAmount = 200;
} etc...
答案 0 :(得分:10)
您可以使用Math.log10
来标准化所有值,然后再执行“精彩数字”搜索,如下所示:
[编辑] 我刚刚意识到你使用的是Java而不是C#,所以我修改了一下代码。我没有编译器来测试它,但无论如何你应该得到一般的想法:
static double getNicerNumber(double val)
{
// get the first larger power of 10
var nice = Math.pow(10, Math.ceiling(Math.log10(val)));
// scale the power to a "nice enough" value
if (val < 0.25 * nice)
nice = 0.25 * nice;
else if (val < 0.5 * nice)
nice = 0.5 * nice;
return nice;
}
// test program:
static void main(string[] args)
{
double[] values =
{
0.1, 0.2, 0.7,
1, 2, 9,
25, 58, 99,
158, 267, 832
};
for (var val : values)
System.out.printf("$%.2f --> $%.2f%n", val, getNicerNumber(val));
}
这将打印如下内容:
0,1 --> 0,1 0,2 --> 0,25 0,7 --> 1 1 --> 1 2 --> 2,5 9 --> 10 25 --> 50 58 --> 100 99 --> 100 158 --> 250 267 --> 500 832 --> 1000
答案 1 :(得分:3)
我更喜欢以下Groo的方法,因为它将267转为275而不是500.它基本上是向第一个数字舍入,然后是最接近10的幂的四分之一。
static double round_pretty(double val) {
var fraction = 1;
var log = Math.floor(Math.log10(val));
// This keeps from adding digits after the decimal
if(log > 1) {
fraction = 4;
}
return Math.round(val * fraction * Math.pow(10, -log))
/ fraction / Math.pow(10, -log);
}
输出如下:
0.01 -> 0.01
0.025 -> 0.03 (Groo's does 0.025)
0.1 -> 0.1
0.2 -> 0.2 (Groo's does 0.25)
0.49 -> 0.5
0.5 -> 0.5 (Groo's does 1)
0.51 -> 0.5 (Groo's does 1)
0.7 -> 0.7 (Groo's does 1)
1 -> 1
2 -> 2 (Groo's does 2.5)
9 -> 9
23.07 -> 20
25 -> 30
49 -> 50
50 -> 50 (Groo's does 100 here)
58 -> 60
94 -> 90
95 -> 100
99 -> 100
100 -> 100
109 -> 100 (Groo's does 250 here)
158 -> 150
249 -> 250
267 -> 275
832 -> 825
1234567 -> 1250000
1499999 -> 1500000
1625000 -> 1750000
答案 2 :(得分:0)
我提出了这个非常粗略的解决方案,它为我刚才测试的所有案例返回了正确的值:
public static double foo(long value) {
for (double i = 0.2; true; i *= 5) {
if (i >= value) {
return i / 5;
}
}
}
虽然我必须承认Groo发布的数学解决方案会更漂亮。 ;)