如何获得一个int数的位数?

有没有一个整洁的方法来获得一个int的长度?

int length = String.valueOf(1000).length(); 

你的基于string的解决scheme是完全正确的,没有什么“不整洁”的。 你必须在math上认识到,数字没有长度,也没有数字。 长度和数字都是特定基数(即string)中数字的物理表示的属性。

一个基于对数的解决scheme可以完成(一些)基于string的解决scheme在内部执行的相同的事情,而且可能会这样做(微不足道),因为它只产生长度并忽略数字。 但是我并不认为它的意图更清楚 – 这是最重要的因素。

对数是你的朋友:

 int n = 1000; int length = (int)(Math.log10(n)+1); 

NB:只对n> 0有效。

最快的方法:分而治之。

假设你的范围是0到MAX_INT,那么你有1到10个数字。 你可以使用分而治之来接近这个间隔,每个input最多可以进行4次比较。 首先,将[1..10]分为[1..5]和[6..10]进行一次比较,然后使用一次比较将每个长度为5的间隔分成一个长度为3和一个长度为2的间隔。 长度为2的区间需要再次比较(总共3次比较),长度为3的区间可以分为长度1区间(解)和长度2区间。 所以,你需要3或4比较。

没有分区,没有浮点操作,没有昂贵的对数,只有整数比较。

代码(长而快):

 if (n < 100000){ // 5 or less if (n < 100){ // 1 or 2 if (n < 10) return 1; else return 2; }else{ // 3 or 4 or 5 if (n < 1000) return 3; else{ // 4 or 5 if (n < 10000) return 4; else return 5; } } } else { // 6 or more if (n < 10000000) { // 6 or 7 if (n < 1000000) return 6; else return 7; } else { // 8 to 10 if (n < 100000000) return 8; else { // 9 or 10 if (n < 1000000000) return 9; else return 10; } } } 

基准testing(在JVM热身之后) – 查看下面的代码,了解如何运行基准testing:

  1. 基线方法(使用String.length):2145ms
  2. log10方法:711ms =比基线快3.02倍
  3. 重复分割:2797ms =比基线快0.77倍
  4. 分而治之:74ms = 28.99
    比基线快了几倍

完整代码:

 public static void main(String[] args) throws Exception { // validate methods: for (int i = 0; i < 1000; i++) if (method1(i) != method2(i)) System.out.println(i); for (int i = 0; i < 1000; i++) if (method1(i) != method3(i)) System.out.println(i + " " + method1(i) + " " + method3(i)); for (int i = 333; i < 2000000000; i += 1000) if (method1(i) != method3(i)) System.out.println(i + " " + method1(i) + " " + method3(i)); for (int i = 0; i < 1000; i++) if (method1(i) != method4(i)) System.out.println(i + " " + method1(i) + " " + method4(i)); for (int i = 333; i < 2000000000; i += 1000) if (method1(i) != method4(i)) System.out.println(i + " " + method1(i) + " " + method4(i)); // work-up the JVM - make sure everything will be run in hot-spot mode allMethod1(); allMethod2(); allMethod3(); allMethod4(); // run benchmark Chronometer c; c = new Chronometer(true); allMethod1(); c.stop(); long baseline = c.getValue(); System.out.println(c); c = new Chronometer(true); allMethod2(); c.stop(); System.out.println(c + " = " + StringTools.formatDouble((double)baseline / c.getValue() , "0.00") + " times faster than baseline"); c = new Chronometer(true); allMethod3(); c.stop(); System.out.println(c + " = " + StringTools.formatDouble((double)baseline / c.getValue() , "0.00") + " times faster than baseline"); c = new Chronometer(true); allMethod4(); c.stop(); System.out.println(c + " = " + StringTools.formatDouble((double)baseline / c.getValue() , "0.00") + " times faster than baseline"); } private static int method1(int n) { return Integer.toString(n).length(); } private static int method2(int n) { if (n == 0) return 1; return (int)(Math.log10(n) + 1); } private static int method3(int n) { if (n == 0) return 1; int l; for (l = 0 ; n > 0 ;++l) n /= 10; return l; } private static int method4(int n) { if (n < 100000) { // 5 or less if (n < 100) { // 1 or 2 if (n < 10) return 1; else return 2; } else { // 3 or 4 or 5 if (n < 1000) return 3; else { // 4 or 5 if (n < 10000) return 4; else return 5; } } } else { // 6 or more if (n < 10000000) { // 6 or 7 if (n < 1000000) return 6; else return 7; } else { // 8 to 10 if (n < 100000000) return 8; else { // 9 or 10 if (n < 1000000000) return 9; else return 10; } } } } private static int allMethod1() { int x = 0; for (int i = 0; i < 1000; i++) x = method1(i); for (int i = 1000; i < 100000; i += 10) x = method1(i); for (int i = 100000; i < 1000000; i += 100) x = method1(i); for (int i = 1000000; i < 2000000000; i += 200) x = method1(i); return x; } private static int allMethod2() { int x = 0; for (int i = 0; i < 1000; i++) x = method2(i); for (int i = 1000; i < 100000; i += 10) x = method2(i); for (int i = 100000; i < 1000000; i += 100) x = method2(i); for (int i = 1000000; i < 2000000000; i += 200) x = method2(i); return x; } private static int allMethod3() { int x = 0; for (int i = 0; i < 1000; i++) x = method3(i); for (int i = 1000; i < 100000; i += 10) x = method3(i); for (int i = 100000; i < 1000000; i += 100) x = method3(i); for (int i = 1000000; i < 2000000000; i += 200) x = method3(i); return x; } private static int allMethod4() { int x = 0; for (int i = 0; i < 1000; i++) x = method4(i); for (int i = 1000; i < 100000; i += 10) x = method4(i); for (int i = 100000; i < 1000000; i += 100) x = method4(i); for (int i = 1000000; i < 2000000000; i += 200) x = method4(i); return x; } 

再次,基准:

  1. 基线方法(使用String.length):2145ms
  2. log10方法:711ms =比基线快3.02倍
  3. 重复分割:2797ms =比基线快0.77倍
  4. 分而治之:74ms = 28.99
    比基线快了几倍

编辑:在我编写基准testing之后,我从Java 6的Integer.toString中偷袭了一个尖峰,我发现它使用:

 final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, Integer.MAX_VALUE }; // Requires positive x static int stringSize(int x) { for (int i=0; ; i++) if (x <= sizeTable[i]) return i+1; } 

我以我的分而治之scheme为基准:

  1. 分而治之:104ms
  2. Java 6解决scheme – 迭代和比较:406ms

我的速度快了4倍。

对你的基准testing有两点评论:Java是一个复杂的环境,即时编译和垃圾回收等等,为了得到公平的比较,每当我运行基准testing时,我总是:(a)把两个testing在循环中按顺序运行5次或10次。 通常第二次通过循环的运行时间与第一次完全不同。 和(b)每个“方法”后,我做一个System.gc()来尝试触发一个垃圾收集。 否则,第一种方法可能会产生一堆对象,但不足以强制垃圾收集,然后第二种方法创build一些对象,堆耗尽,垃圾收集运行。 然后第二种方法是“收取”第一种方法留下的垃圾。 非常不公平!

也就是说,在这个例子中,以上都没有显着的区别。

不pipe有没有这些修改,我都得到了与你不同的结果。 当我运行这个时,是的,toString方法的运行时间是6400到6600毫秒,而日志方法topok是200到20400毫秒。 日志方法比我慢了3倍,而不是稍微快一点。

请注意,这两种方法涉及到非常不同的成本,所以这不是完全令人震惊的:toString方法将创build大量临时对象,必须清理,而日志方法需要更多的计算。 所以也许不同的是,在内存较less的机器上,toString需要更多的垃圾回收,而在处理器较慢的机器上,日志的额外计算会更加痛苦。

我也尝试了第三种方法。 我写了这个小函数:

 static int numlength(int n) { if (n == 0) return 1; int l; n=Math.abs(n); for (l=0;n>0;++l) n/=10; return l; } 

运行在1600到1900毫秒之间 – 小于1/3的toString方法,以及1/10的日志方式在我的机器上。

如果你的数字范围很广,你可以通过开始除以1,000或1,000,000来进一步加速,以减less循环的次数。 我没有玩过。

由于一个整数的基数为10的位数只是1 + truncate(log10(number)) ,所以你可以这样做:

 public class Test { public static void main(String[] args) { final int number = 1234; final int digits = 1 + (int)Math.floor(Math.log10(number)); System.out.println(digits); } } 

编辑,因为我上次编辑修正了代码示例,但不是描述。

使用Java

 int nDigits = Math.floor(Math.log10(Math.abs(the_integer))) + 1; 

使用import java.lang.Math.*; 在一开始的时候

使用C.

 int nDigits = floor(log10(abs(the_integer))) + 1; 

使用inclue math.h开头

我可以试试吗? ;)

基于德克的解决scheme

 final int digits = number==0?1:(1 + (int)Math.floor(Math.log10(Math.abs(number)))); 

玛丽安的解决scheme适用于型号(最多9,223,372,036,854,775,807),以防有人想要复制和粘贴。 在这个程序中,我写了10000个以上的数字的可能性要大得多,所以我为他们做了一个特定的分支。 无论如何,这不会产生显着的差异。

 public static int numberOfDigits (long n) { // Guessing 4 digit numbers will be more probable. // They are set in the first branch. if (n < 10000L) { // from 1 to 4 if (n < 100L) { // 1 or 2 if (n < 10L) { return 1; } else { return 2; } } else { // 3 or 4 if (n < 1000L) { return 3; } else { return 4; } } } else { // from 5 a 20 (albeit longs can't have more than 18 or 19) if (n < 1000000000000L) { // from 5 to 12 if (n < 100000000L) { // from 5 to 8 if (n < 1000000L) { // 5 or 6 if (n < 100000L) { return 5; } else { return 6; } } else { // 7 u 8 if (n < 10000000L) { return 7; } else { return 8; } } } else { // from 9 to 12 if (n < 10000000000L) { // 9 or 10 if (n < 1000000000L) { return 9; } else { return 10; } } else { // 11 or 12 if (n < 100000000000L) { return 11; } else { return 12; } } } } else { // from 13 to ... (18 or 20) if (n < 10000000000000000L) { // from 13 to 16 if (n < 100000000000000L) { // 13 or 14 if (n < 10000000000000L) { return 13; } else { return 14; } } else { // 15 or 16 if (n < 1000000000000000L) { return 15; } else { return 16; } } } else { // from 17 to ...¿20? if (n < 1000000000000000000L) { // 17 or 18 if (n < 100000000000000000L) { return 17; } else { return 18; } } else { // 19? Can it be? // 10000000000000000000L is'nt a valid long. return 19; } } } } } 

简单的老math怎么样? 除以10,直到达到0。

 public static int getSize(long number) { int count = 0; while (number > 0) { count += 1; number = (number / 10); } return count; } 

目前还不能发表评论,所以我会作为一个单独的答案发布。

基于对数的解决scheme不会计算非常大的长整数的正确位数,例如:

 long n = 99999999999999999L; // correct answer: 17 int numberOfDigits = String.valueOf(n).length(); // incorrect answer: 18 int wrongNumberOfDigits = (int) (Math.log10(n) + 1); 

以对数为基础的解决scheme计算大整数的数字不正确

好奇,我试图用它作为基准

 import org.junit.Test; import static org.junit.Assert.*; public class TestStack1306727 { @Test public void bench(){ int number=1000; int a= String.valueOf(number).length(); int b= 1 + (int)Math.floor(Math.log10(number)); assertEquals(a,b); int i=0; int s=0; long startTime = System.currentTimeMillis(); for(i=0, s=0; i< 100000000; i++){ a= String.valueOf(number).length(); s+=a; } long stopTime = System.currentTimeMillis(); long runTime = stopTime - startTime; System.out.println("Run time 1: " + runTime); System.out.println("s: "+s); startTime = System.currentTimeMillis(); for(i=0,s=0; i< 100000000; i++){ b= number==0?1:(1 + (int)Math.floor(Math.log10(Math.abs(number)))); s+=b; } stopTime = System.currentTimeMillis(); runTime = stopTime - startTime; System.out.println("Run time 2: " + runTime); System.out.println("s: "+s); assertEquals(a,b); } } 

结果是:

运行时间1:6765
 s:400000000
运行时间2:6000
 s:400000000

现在我只是想知道我的基准testing是否真的有意义,但是在基准testing本身的多次testing中,我得到了一致的结果(差异在一个毫秒内)。:)看起来好像没有用,试图优化这个…


编辑:遵循ptomli的评论,我在上面的代码中用'i'replace了'number',并在5次运行中得到了以下结果:

运行时间1:11500
 s:788888890
运行时间2:8547
 s:788888890

运行时间1:11485
 s:788888890
运行时间2:8547
 s:788888890

运行时间1:11469
 s:788888890
运行时间2:8547
 s:788888890

运行时间1:11500
 s:788888890
运行时间2:8547
 s:788888890

运行时间1:11484
 s:788888890
运行时间2:8547
 s:788888890

玛丽安的解决scheme,现在与三元:

  public int len(int n){ return (n<100000)?((n<100)?((n<10)?1:2):(n<1000)?3:((n<10000)?4:5)):((n<10000000)?((n<1000000)?6:7):((n<100000000)?8:((n<1000000000)?9:10))); } 

因为我们可以。

这个recursion方法呢?

  private static int length = 0; public static int length(int n) { length++; if((n / 10) < 10) { length++; } else { length(n / 10); } return length; } 

简单scheme:

 public class long_length { long x,l=1,n; for (n=10;n<x;n*=10){ if (x/n!=0){ l++; } } System.out.print(l); } 

一个很简单的解决scheme

 public int numLength(int n) { for (int length = 1; n % Math.pow(10, length) != n; length++) {} return length; } 

或者,您可以检查长度是否大于或小于所需的数字。

  public void createCard(int cardNumber, int cardStatus, int customerId) throws SQLException { if(cardDao.checkIfCardExists(cardNumber) == false) { if(cardDao.createCard(cardNumber, cardStatus, customerId) == true) { System.out.println("Card created successfully"); } else { } } else { System.out.println("Card already exists, try with another Card Number"); do { System.out.println("Enter your new Card Number: "); scan = new Scanner(System.in); int inputCardNumber = scan.nextInt(); cardNumber = inputCardNumber; } while(cardNumber < 95000000); cardDao.createCard(cardNumber, cardStatus, customerId); } } 

}

我还没有看到基于乘法的解决scheme。 对数,divison和基于string的解决scheme对数以百万计的testing用例来说将变得相当笨拙,所以这里是一个ints

 /** * Returns the number of digits needed to represents an {@code int} value in * the given radix, disregarding any sign. */ public static int len(int n, int radix) { radixCheck(radix); // if you want to establish some limitation other than radix > 2 n = Math.abs(n); int len = 1; long min = radix - 1; while (n > min) { n -= min; min *= radix; len++; } return len; } 

在基数10中,这是有效的,因为n基本上与9,99,999 …进行比较,因为最小值是9,90,900 …并且n被减去9,90,900 …

不幸的是,这只是通过replace由于溢出导致的每个int实例而不能移植。 另一方面,它恰好发生在基地2和10(但是对其他大多数基地而言严重失败)。 你将需要一个溢出点的查找表(或一个划分testing…电子表格)

 /** * For radices 2 &le r &le Character.MAX_VALUE (36) */ private static long[] overflowpt = {-1, -1, 4611686018427387904L, 8105110306037952534L, 3458764513820540928L, 5960464477539062500L, 3948651115268014080L, 3351275184499704042L, 8070450532247928832L, 1200757082375992968L, 9000000000000000000L, 5054470284992937710L, 2033726847845400576L, 7984999310198158092L, 2022385242251558912L, 6130514465332031250L, 1080863910568919040L, 2694045224950414864L, 6371827248895377408L, 756953702320627062L, 1556480000000000000L, 3089447554782389220L, 5939011215544737792L, 482121737504447062L, 839967991029301248L, 1430511474609375000L, 2385723916542054400L, 3902460517721977146L, 6269893157408735232L, 341614273439763212L, 513726300000000000L, 762254306892144930L, 1116892707587883008L, 1617347408439258144L, 2316231840055068672L, 3282671350683593750L, 4606759634479349760L}; public static int len(long n, int radix) { radixCheck(radix); n = abs(n); int len = 1; long min = radix - 1; while (n > min) { len++; if (min == overflowpt[radix]) break; n -= min; min *= radix; } return len; } 

用devise(根据问题)。 这是一个分而治之的交替。 我们将首先定义一个枚举(考虑它只适用于一个unsigned int)。

 public enum IntegerLength { One((byte)1,10), Two((byte)2,100), Three((byte)3,1000), Four((byte)4,10000), Five((byte)5,100000), Six((byte)6,1000000), Seven((byte)7,10000000), Eight((byte)8,100000000), Nine((byte)9,1000000000); byte length; int value; IntegerLength(byte len,int value) { this.length = len; this.value = value; } public byte getLenght() { return length; } public int getValue() { return value; } } 

现在我们将定义一个类,它通过枚举的值并比较并返回适当的长度。

 public class IntegerLenght { public static byte calculateIntLenght(int num) { for(IntegerLength v : IntegerLength.values()) { if(num < v.getValue()){ return v.getLenght(); } } return 0; } } 

该解决scheme的运行时间与分而治之的方法相同。

input数字并创build一个Arraylist ,while循环将把所有数字logging到Arraylist 。 然后我们可以取出数组的大小,这将是您input的整数值的长度。

 ArrayList<Integer> a=new ArrayList<>(); while(number > 0) { remainder = num % 10; a.add(remainder); number = number / 10; } int m=a.size(); 

简单的recursion方式

 int get_int_lenght(current_lenght, value) { if (value / 10 < 10) return (current_lenght + 1); return (get_int_lenght(current_lenght + 1, value)) } 

未经testing

我们可以使用recursion循环来实现这一点

  public static int digitCount(int numberInput, int i) { while (numberInput > 0) { i++; numberInput = numberInput / 10; digitCount(numberInput, i); } return i; } public static void printString() { int numberInput = 1234567; int digitCount = digitCount(numberInput, 0); System.out.println("Count of digit in ["+numberInput+"] is ["+digitCount+"]"); } 
  int num = 02300; int count = 0; while(num>0){ if(num == 0) break; num=num/10; count++; } System.out.println(count); 

这是一个非常简单的方法,我做了任何数字的作品:

 public static int numberLength(int userNumber) { int numberCounter = 10; boolean condition = true; int digitLength = 1; while (condition) { int numberRatio = userNumber / numberCounter; if (numberRatio < 1) { condition = false; } else { digitLength++; numberCounter *= 10; } } return digitLength; } 

它的工作方式是数字计数器variables是10 = 1数字空间。 例如.1 =十进制=> 1个数字空间。 因此,如果你有int number = 103342; 你会得到6,因为那相当于0.000001个空格。 另外,有没有人有一个更好的numberCountervariables名? 我想不出什么更好的。

编辑:只是想到了一个更好的解释。 基本上这个while循环正在做的是让你的数字除以10,直到它小于1。 从本质上讲,当你将数字除以10时,你将把它移回一个数字空间,所以你简单地把它除以10,直到你的数字中的数字达到<1。

这里有另一个版本可以计算小数的数量:

 public static int repeatingLength(double decimalNumber) { int numberCounter = 1; boolean condition = true; int digitLength = 1; while (condition) { double numberRatio = decimalNumber * numberCounter; if ((numberRatio - Math.round(numberRatio)) < 0.0000001) { condition = false; } else { digitLength++; numberCounter *= 10; } } return digitLength - 1; } 

一个人想这样做主要是因为他/她想“呈现”它,这主要意味着它最终需要被明确地或隐含地“串”(或以另一种方式转换); 然后才能呈现(例如打印)。

如果是这种情况,那就试着做一些必要的“toString”,然后对这些位进行计数。

我这样做了,得到了数字的长度

 String Temp=IntegerVariable+""; System.out.println(Temp.length()); 

你可以使用连续的十进制数字:

 int a=0; if (no < 0) { no = -no; } else if (no == 0) { no = 1; } while (no > 0) { no = no / 10; a++; } System.out.println("Number of digits in given number is: "+a); 

尝试将int转换为一个string ,然后获取string的长度。 这应该得到int的长度。

 public static int intLength(int num){ String n = Integer.toString(num); int newNum = n.length(); return newNum; }