获取int的长度是否比这种方法更简洁?
int length = String.valueOf(1000).length();
答案 0 :(得分:316)
你的基于String的解决方案完全没问题,没有什么“不整齐”的。你必须在数学上认识到,数字没有长度,也没有数字。长度和数字都是特定基数中的数字的物理表示的属性,即字符串。
基于对数的解决方案确实(某些)基于字符串的解决方案在内部执行相同的操作,并且可能更快(不显着)更快,因为它只产生长度并忽略数字。但我实际上并不认为它的意图更清晰 - 这是最重要的因素。
答案 1 :(得分:248)
对数是你的朋友:
int n = 1000;
int length = (int)(Math.log10(n)+1);
注意:仅对n>有效0
答案 2 :(得分:149)
最快的方法:分而治之。
假设您的范围是0到MAX_INT,那么您有1到10位数。您可以使用除法和征服来处理此间隔,每个输入最多可进行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;
}
}
}
基准测试(在JVM热身之后) - 请参阅下面的代码以了解基准测试的运行方式:
完整代码:
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;
}
再次,基准:
修改强> 在我编写基准测试后,我从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;
}
我根据我的分而治之的解决方案对其进行了基准测试:
答案 3 :(得分:11)
关于您的基准测试的两条评论:Java是一个复杂的环境,即时编译和垃圾收集等等,所以为了得到公平的比较,每当我运行基准测试时,我总是:(a)附上循环中的两个测试按顺序运行它们5或10次。第二次通过循环的运行时通常与第一次完全不同。并且(b)在每个“方法”之后,我做一个System.gc()来尝试触发垃圾收集。否则,第一种方法可能会生成一堆对象,但还不足以强制进行垃圾收集,然后第二种方法会创建一些对象,堆耗尽,垃圾收集运行。然后第二种方法被“收费”用于拾取第一种方法留下的垃圾。非常不公平!
尽管如此,上述两个都没有在这个例子中产生显着差异。
无论有没有这些修改,我得到的结果都与你有很大不同。当我运行它时,是的,toString方法的运行时间为6400到6600毫秒,而日志方法则超过20,000到20,400毫秒。对于我来说,日志方法的速度要慢一些,而不是稍微快一点。
请注意,这两种方法涉及非常不同的成本,因此这并不完全令人震惊:toString方法将创建许多必须清理的临时对象,而日志方法需要更加强烈的计算。所以可能不同的是,在内存较少的机器上,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毫秒 - 小于toString方法的1/3,以及我机器上的对数方法的1/10。
如果你有广泛的数字,你可以通过开始除以1,000或1,000,000来进一步加快速度,以减少循环的次数。我没玩过。
答案 4 :(得分:9)
使用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
答案 5 :(得分:8)
由于整数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);
}
}
已编辑,因为我上次编辑修复了代码示例,但没有修改说明。
答案 6 :(得分:7)
还不能发表评论,所以我会发布一个单独的答案。
基于对数的解决方案不计算非常大的长整数的正确位数,例如:
long n = 99999999999999999L;
// correct answer: 17
int numberOfDigits = String.valueOf(n).length();
// incorrect answer: 18
int wrongNumberOfDigits = (int) (Math.log10(n) + 1);
Logarithm-based solution calculates incorrect number of digits in large integers
答案 7 :(得分:5)
Marian的解决方案适用于长类型号码(最多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;
}
}
}
}
}
答案 8 :(得分:3)
普通老数学怎么样?除以10直到达到0。
public static int getSize(long number) {
int count = 0;
while (number > 0) {
count += 1;
number = (number / 10);
}
return count;
}
答案 9 :(得分:3)
我可以试试吗? ;)
基于Dirk的解决方案
final int digits = number==0?1:(1 + (int)Math.floor(Math.log10(Math.abs(number))));
答案 10 :(得分:2)
玛丽安的解决方案,现在与三元:
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)));
}
因为 我们可以。
答案 11 :(得分:2)
另一种字符串方法。简短而甜美-适用于任何整数n
。
int length = ("" + n).length();
答案 12 :(得分:1)
好奇,我试图对它进行基准测试......
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);
}
}
结果是:
Run time 1: 6765 s: 400000000 Run time 2: 6000 s: 400000000
现在我不知道我的基准测试是否真的意味着什么,但我确实在基准测试本身的多次运行中获得了一致的结果(在一个ms内变化)... :)看起来尝试优化它是没用的。 ..
编辑:在ptomli的评论之后,我在上面的代码中将'number'替换为'i',并通过5次替补获得了以下结果:
Run time 1: 11500 s: 788888890 Run time 2: 8547 s: 788888890 Run time 1: 11485 s: 788888890 Run time 2: 8547 s: 788888890 Run time 1: 11469 s: 788888890 Run time 2: 8547 s: 788888890 Run time 1: 11500 s: 788888890 Run time 2: 8547 s: 788888890 Run time 1: 11484 s: 788888890 Run time 2: 8547 s: 788888890
答案 13 :(得分:1)
没有String API,没有utils,没有类型转换,仅是纯Java迭代->
public static int getNumberOfDigits(int input) {
int numOfDigits = 1;
int base = 1;
while (input >= base * 10) {
base = base * 10;
numOfDigits++;
}
return numOfDigits;
}
如果愿意,您可以追求更大的价值。
答案 14 :(得分:0)
我看到人们使用String库,甚至使用Integer类。没什么错,但是获取数字位数的算法并不那么复杂。在此示例中,我使用了long,但使用int可以正常工作。
private static int getLength(long num) {
int count = 1;
while (num >= 10) {
num = num / 10;
count++;
}
return count;
}
答案 15 :(得分:0)
我在查看Integer.java
源代码之后编写了此函数。
private static int stringSize(int x) {
final int[] sizeTable = {9, 99, 999, 9_999, 99_999, 999_999, 9_999_999,
99_999_999, 999_999_999, Integer.MAX_VALUE};
for (int i = 0; ; ++i) {
if (x <= sizeTable[i]) {
return i + 1;
}
}
}
答案 16 :(得分:0)
计算 int
变量中位数的有效方法之一是定义一个方法 digitsCounter,其中包含所需数量的条件语句。
方法很简单,我们将检查 n
数字可以位于的每个范围:
0 : 9 是 Single
位数字
10 : 99 是 Double
位数字
100 : 999 是 Triple
位数字等等...
static int digitsCounter(int N)
{ // N = Math.abs(N); // if `N` is -ve
if (0 <= N && N <= 9) return 1;
if (10 <= N && N <= 99) return 2;
if (100 <= N && N <= 999) return 3;
if (1000 <= N && N <= 9999) return 4;
if (10000 <= N && N <= 99999) return 5;
if (100000 <= N && N <= 999999) return 6;
if (1000000 <= N && N <= 9999999) return 7;
if (10000000 <= N && N <= 99999999) return 8;
if (100000000 <= N && N <= 999999999) return 9;
return 10;
}
更简洁的方法是取消对下限的检查,因为如果我们按顺序进行,则不需要这样做。
static int digitsCounter(int N)
{
N = N < 0 ? -N : N;
if (N <= 9) return 1;
if (N <= 99) return 2;
if (N <= 999) return 3;
if (N <= 9999) return 4;
if (N <= 99999) return 5;
if (N <= 999999) return 6;
if (N <= 9999999) return 7;
if (N <= 99999999) return 8;
if (N <= 999999999) return 9;
return 10; // Max possible digits in an 'int'
}
答案 17 :(得分:0)
一个人想这样做主要是因为他/她想要“呈现”它,这主要意味着它最终需要明确或隐含地“toString-ed”(或以另一种方式转换)无论如何;在它出现之前(例如打印)。
如果是这种情况,那么只需尝试将必要的“toString”显式化并计算位数。
答案 18 :(得分:0)
我们可以使用递归循环来实现这个目的
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+"]");
}
答案 19 :(得分:0)
我还没有看到基于乘法的解决方案。对数,分区和基于字符串的解决方案对于数以百万计的测试用例将变得相当笨拙,因此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 ......因为min是9,90,900 ......并且n被减去9,90,900 ...... < / p>
不幸的是,仅仅因为溢出而替换long
的每个实例,都无法移植到int
。另一方面,它恰好发生将用于基地2和10(但是对于大多数其他基地而言严重失败)。您需要一个溢出点查找表(或分区测试... ew)
/**
* 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;
}
答案 20 :(得分:0)
或者你可以检查长度是否大于或小于所需的数字。
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);
}
}
}
答案 21 :(得分:0)
设计(基于问题)。这是一种分而治之的替代品。我们首先定义一个枚举(考虑它仅用于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;
}
}
此解决方案的运行时间与分而治之的方法相同。
答案 22 :(得分:0)
一个非常简单的解决方案:
public int numLength(int n) {
for (int length = 1; n % Math.pow(10, length) != n; length++) {}
return length;
}
答案 23 :(得分:0)
简单的解决方案:
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);
}
答案 24 :(得分:0)
这种递归方法怎么样?
private static int length = 0;
public static int length(int n) {
length++;
if((n / 10) < 10) {
length++;
} else {
length(n / 10);
}
return length;
}
答案 25 :(得分:-1)
简单的递归方式
int get_int_lenght(current_lenght, value)
{
if (value / 10 < 10)
return (current_lenght + 1);
return (get_int_lenght(current_lenght + 1, value))
}
未经测试
答案 26 :(得分:-1)
int num = 02300;
int count = 0;
while(num>0){
if(num == 0) break;
num=num/10;
count++;
}
System.out.println(count);
答案 27 :(得分:-2)
您可以使用连续除以10的数字:
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);
答案 28 :(得分:-2)
输入数字并创建Arraylist
,while循环会将所有数字记录到Arraylist
。然后我们可以取出数组的大小,这将是你输入的整数值的长度。
ArrayList<Integer> a=new ArrayList<>();
while(number > 0)
{
remainder = num % 10;
a.add(remainder);
number = number / 10;
}
int m=a.size();
答案 29 :(得分:-2)
这是一个非常简单的方法,适用于任何数字:
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;
}
它的工作方式是数字计数器变量是10 = 1位数空间。例如.1 = 1十分=> 1位数的空间。因此,如果你有int number = 103342;
,你将获得6,因为这相当于.000001空格。此外,是否有人为numberCounter
提供了更好的变量名称?我想不出更好的事情。
编辑:想到更好的解释。基本上这个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;
}
答案 30 :(得分:-3)
尝试将 int 转换为字符串,然后获取字符串的长度。那应该得到 int 的长度。
public static int intLength(int num){
String n = Integer.toString(num);
int newNum = n.length();
return newNum;
}