到最近的好号码

我正在编写一个应用程序,需要将标签舍入到最近的’nice’数字。 我将在下面放一些代码来certificate这一点,但我的问题是我使用了一系列其他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... 

在进行“好数”搜索之前,您可以使用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 

我更喜欢以下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 

我想出了这个非常粗略的解决方案,它为我刚才测试的所有案例返回了正确的值:

 public static double foo(long value) { for (double i = 0.2; true; i *= 5) { if (i >= value) { return i / 5; } } } 

虽然我必须承认Groo发布的数学解决方案会更漂亮。 ;)