C #에서 숫자의 총 자릿수를 어떻게 구할 수 있습니까? 예를 들어, 숫자 887979789는 9 자리 숫자입니다.
답변
문자열로 변환하지 않고 시도해 볼 수 있습니다.
Math.Ceiling(Math.Log10(n));
ysap의 의견에 따른 수정 :
Math.Floor(Math.Log10(n) + 1);
답변
이 시도:
myint.ToString().Length
작동합니까?
답변
해결책
다음 확장 방법 중 하나가 작업을 수행합니다. 모두 빼기 기호를 숫자로 간주하고 가능한 모든 입력 값에 대해 올바르게 작동합니다. .NET Framework 및 .NET Core에서도 작동합니다. 그러나 선택한 플랫폼 / 프레임 워크에 따라 관련 성능 차이가 있습니다 (아래에서 설명).
Int32 버전 :
public static class Int32Extensions
{
// IF-CHAIN:
public static int Digits_IfChain(this int n)
{
if (n >= 0)
{
if (n < 10) return 1;
if (n < 100) return 2;
if (n < 1000) return 3;
if (n < 10000) return 4;
if (n < 100000) return 5;
if (n < 1000000) return 6;
if (n < 10000000) return 7;
if (n < 100000000) return 8;
if (n < 1000000000) return 9;
return 10;
}
else
{
if (n > -10) return 2;
if (n > -100) return 3;
if (n > -1000) return 4;
if (n > -10000) return 5;
if (n > -100000) return 6;
if (n > -1000000) return 7;
if (n > -10000000) return 8;
if (n > -100000000) return 9;
if (n > -1000000000) return 10;
return 11;
}
}
// USING LOG10:
public static int Digits_Log10(this int n) =>
n == 0 ? 1 : (n > 0 ? 1 : 2) + (int)Math.Log10(Math.Abs((double)n));
// WHILE LOOP:
public static int Digits_While(this int n)
{
int digits = n < 0 ? 2 : 1;
while ((n /= 10) != 0) ++digits;
return digits;
}
// STRING CONVERSION:
public static int Digits_String(this int n) =>
n.ToString().Length;
}
Int64 버전 :
public static class Int64Extensions
{
// IF-CHAIN:
public static int Digits_IfChain(this long n)
{
if (n >= 0)
{
if (n < 10L) return 1;
if (n < 100L) return 2;
if (n < 1000L) return 3;
if (n < 10000L) return 4;
if (n < 100000L) return 5;
if (n < 1000000L) return 6;
if (n < 10000000L) return 7;
if (n < 100000000L) return 8;
if (n < 1000000000L) return 9;
if (n < 10000000000L) return 10;
if (n < 100000000000L) return 11;
if (n < 1000000000000L) return 12;
if (n < 10000000000000L) return 13;
if (n < 100000000000000L) return 14;
if (n < 1000000000000000L) return 15;
if (n < 10000000000000000L) return 16;
if (n < 100000000000000000L) return 17;
if (n < 1000000000000000000L) return 18;
return 19;
}
else
{
if (n > -10L) return 2;
if (n > -100L) return 3;
if (n > -1000L) return 4;
if (n > -10000L) return 5;
if (n > -100000L) return 6;
if (n > -1000000L) return 7;
if (n > -10000000L) return 8;
if (n > -100000000L) return 9;
if (n > -1000000000L) return 10;
if (n > -10000000000L) return 11;
if (n > -100000000000L) return 12;
if (n > -1000000000000L) return 13;
if (n > -10000000000000L) return 14;
if (n > -100000000000000L) return 15;
if (n > -1000000000000000L) return 16;
if (n > -10000000000000000L) return 17;
if (n > -100000000000000000L) return 18;
if (n > -1000000000000000000L) return 19;
return 20;
}
}
// USING LOG10:
public static int Digits_Log10(this long n) =>
n == 0L ? 1 : (n > 0L ? 1 : 2) + (int)Math.Log10(Math.Abs((double)n));
// WHILE LOOP:
public static int Digits_While(this long n)
{
int digits = n < 0 ? 2 : 1;
while ((n /= 10L) != 0L) ++digits;
return digits;
}
// STRING CONVERSION:
public static int Digits_String(this long n) =>
n.ToString().Length;
}
토론
이 답변에는 무작위로 샘플링 된 / 숫자 의 배열을 사용하여 Int32
및 Int64
유형 모두에 대해 수행 된 테스트가 포함 됩니다. 무작위 데이터 세트는 테스트를 실행하기 전에 배열로 사전 처리됩니다.100.000.000
int
long
4 개 가지 방법 중 일관성 검사도 수행되었다위한 MinValue
네거티브 테두리 경우,, -1
, 0
, 1
, 포지티브 테두리 케이스 MaxValue
, 또한 전체 랜덤 데이터 셋. LOG10 방법을 제외하고 위에 제공된 방법에 대한 일관성 테스트는 실패하지 않습니다 (이 내용은 나중에 설명합니다).
테스트는 .NET Framework 4.7.2
및 에서 실행되었습니다 .NET Core 2.2
. 에 x86
와 x64
플랫폼, 64 비트 인텔 프로세서 시스템에서,와 Windows 10
,와와 VS2017 v.15.9.17
. 다음 4 가지 경우는 성능 결과에 동일한 영향을 미칩니다.
.NET Framework (x86)
-
Platform = x86
-
Platform = AnyCPU
,Prefer 32-bit
프로젝트 설정에서 확인 됨
.NET Framework (x64)
-
Platform = x64
-
Platform = AnyCPU
,Prefer 32-bit
프로젝트 설정에서 선택 취소됨
.NET Core (x86)
-
"C:\Program Files (x86)\dotnet\dotnet.exe" bin\Release\netcoreapp2.2\ConsoleApp.dll
-
"C:\Program Files (x86)\dotnet\dotnet.exe" bin\x86\Release\netcoreapp2.2\ConsoleApp.dll
.NET Core (x64)
-
"C:\Program Files\dotnet\dotnet.exe" bin\Release\netcoreapp2.2\ConsoleApp.dll
-
"C:\Program Files\dotnet\dotnet.exe" bin\x64\Release\netcoreapp2.2\ConsoleApp.dll
결과
아래의 성능 테스트는 정수가 가정 할 수있는 광범위한 값 사이에 균일 한 값 분포를 생성합니다. 즉, 자릿수가 많은 값을 테스트 할 가능성이 훨씬 더 높습니다. 실제 시나리오에서는 대부분의 값이 작을 수 있으므로 IF-CHAIN이 더 잘 수행되어야합니다. 또한 프로세서는 데이터 세트에 따라 IF-CHAIN 결정을 캐시하고 최적화합니다.
마찬가지로 @AlanSingfield는 주석 섹션에서 지적 상기 LOG10 방법은 주조에 의해 고정되어야했다 double
내부 Math.Abs()
입력 값이 때 경우에 int.MinValue
또는 long.MinValue
.
이 질문을 편집하기 전에 구현 한 초기 성능 테스트와 관련하여 (이미 백만 번 편집해야 함) @ GyörgyKőszeg가 지적한 특정 사례 가 있는데, IF-CHAIN 방법이 LOG10 방법보다 느리게 수행됩니다.
@AlanSingfield가 지적한 문제에 대한 수정 이후 차이의 크기가 훨씬 낮아졌지만 여전히 발생합니다 . 이 수정 (캐스트 추가 double
)은 입력 값이 정확히 -999999999999999999
다음과 같을 때 계산 오류를 발생시킵니다 . 20
대신 LOG10 메서드가 반환 됩니다 19
. LOG10 메서드 if
에는 입력 값이 0 인 경우에 대한 가드 도 있어야합니다 .
LOG10 메서드는 모든 값에 대해 작동하기가 매우 까다롭기 때문에 피해야합니다. 누군가 아래의 모든 일관성 테스트에서 올바르게 작동하도록하는 방법을 찾으면 댓글을 달아주세요!
WHILE 메서드는 또한 더 빠른 최신 리팩토링 버전을 얻었지만 여전히 느립니다 Platform = x86
(지금까지 이유를 찾을 수 없었습니다).
STRING 메서드는 지속적으로 느립니다. 탐욕스럽게 너무 많은 메모리를 할당합니다. 흥미롭게도 .NET Core에서 문자열 할당은 .NET Framework에서보다 훨씬 빠릅니다. 알아 둘만 한.
IF-CHAIN 방법은 99.99 %의 경우에서 다른 모든 방법보다 성능이 우수해야합니다. 그리고 내 개인적인 의견으로는 LOG10 방법이 올바르게 작동하도록 필요한 모든 조정과 다른 두 방법의 나쁜 성능을 고려할 때 최선의 선택입니다.
마지막으로 결과는 다음과 같습니다.
이러한 결과는 하드웨어에 따라 다르기 때문에 특정 경우에 100 % 확신해야하는 경우 자신의 컴퓨터에서 아래 성능 테스트를 실행하는 것이 좋습니다.
테스트 코드
아래는 성능 테스트와 일관성 테스트를위한 코드입니다. .NET Framework 및 .NET Core 모두에 동일한 코드가 사용됩니다.
using System;
using System.Diagnostics;
namespace NumberOfDigits
{
// Performance Tests:
class Program
{
private static void Main(string[] args)
{
Console.WriteLine("\r\n.NET Core");
RunTests_Int32();
RunTests_Int64();
}
// Int32 Performance Tests:
private static void RunTests_Int32()
{
Console.WriteLine("\r\nInt32");
const int size = 100000000;
int[] samples = new int[size];
Random random = new Random((int)DateTime.Now.Ticks);
for (int i = 0; i < size; ++i)
samples[i] = random.Next(int.MinValue, int.MaxValue);
Stopwatch sw1 = new Stopwatch();
sw1.Start();
for (int i = 0; i < size; ++i) samples[i].Digits_IfChain();
sw1.Stop();
Console.WriteLine($"IfChain: {sw1.ElapsedMilliseconds} ms");
Stopwatch sw2 = new Stopwatch();
sw2.Start();
for (int i = 0; i < size; ++i) samples[i].Digits_Log10();
sw2.Stop();
Console.WriteLine($"Log10: {sw2.ElapsedMilliseconds} ms");
Stopwatch sw3 = new Stopwatch();
sw3.Start();
for (int i = 0; i < size; ++i) samples[i].Digits_While();
sw3.Stop();
Console.WriteLine($"While: {sw3.ElapsedMilliseconds} ms");
Stopwatch sw4 = new Stopwatch();
sw4.Start();
for (int i = 0; i < size; ++i) samples[i].Digits_String();
sw4.Stop();
Console.WriteLine($"String: {sw4.ElapsedMilliseconds} ms");
// Start of consistency tests:
Console.WriteLine("Running consistency tests...");
bool isConsistent = true;
// Consistency test on random set:
for (int i = 0; i < samples.Length; ++i)
{
int s = samples[i];
int a = s.Digits_IfChain();
int b = s.Digits_Log10();
int c = s.Digits_While();
int d = s.Digits_String();
if (a != b || c != d || a != c)
{
Console.WriteLine($"Digits({s}): IfChain={a} Log10={b} While={c} String={d}");
isConsistent = false;
break;
}
}
// Consistency test of special values:
samples = new int[]
{
0,
int.MinValue, -1000000000, -999999999, -100000000, -99999999, -10000000, -9999999, -1000000, -999999, -100000, -99999, -10000, -9999, -1000, -999, -100, -99, -10, -9, - 1,
int.MaxValue, 1000000000, 999999999, 100000000, 99999999, 10000000, 9999999, 1000000, 999999, 100000, 99999, 10000, 9999, 1000, 999, 100, 99, 10, 9, 1,
};
for (int i = 0; i < samples.Length; ++i)
{
int s = samples[i];
int a = s.Digits_IfChain();
int b = s.Digits_Log10();
int c = s.Digits_While();
int d = s.Digits_String();
if (a != b || c != d || a != c)
{
Console.WriteLine($"Digits({s}): IfChain={a} Log10={b} While={c} String={d}");
isConsistent = false;
break;
}
}
// Consistency test result:
if (isConsistent)
Console.WriteLine("Consistency tests are OK");
}
// Int64 Performance Tests:
private static void RunTests_Int64()
{
Console.WriteLine("\r\nInt64");
const int size = 100000000;
long[] samples = new long[size];
Random random = new Random((int)DateTime.Now.Ticks);
for (int i = 0; i < size; ++i)
samples[i] = Math.Sign(random.Next(-1, 1)) * (long)(random.NextDouble() * long.MaxValue);
Stopwatch sw1 = new Stopwatch();
sw1.Start();
for (int i = 0; i < size; ++i) samples[i].Digits_IfChain();
sw1.Stop();
Console.WriteLine($"IfChain: {sw1.ElapsedMilliseconds} ms");
Stopwatch sw2 = new Stopwatch();
sw2.Start();
for (int i = 0; i < size; ++i) samples[i].Digits_Log10();
sw2.Stop();
Console.WriteLine($"Log10: {sw2.ElapsedMilliseconds} ms");
Stopwatch sw3 = new Stopwatch();
sw3.Start();
for (int i = 0; i < size; ++i) samples[i].Digits_While();
sw3.Stop();
Console.WriteLine($"While: {sw3.ElapsedMilliseconds} ms");
Stopwatch sw4 = new Stopwatch();
sw4.Start();
for (int i = 0; i < size; ++i) samples[i].Digits_String();
sw4.Stop();
Console.WriteLine($"String: {sw4.ElapsedMilliseconds} ms");
// Start of consistency tests:
Console.WriteLine("Running consistency tests...");
bool isConsistent = true;
// Consistency test on random set:
for (int i = 0; i < samples.Length; ++i)
{
long s = samples[i];
int a = s.Digits_IfChain();
int b = s.Digits_Log10();
int c = s.Digits_While();
int d = s.Digits_String();
if (a != b || c != d || a != c)
{
Console.WriteLine($"Digits({s}): IfChain={a} Log10={b} While={c} String={d}");
isConsistent = false;
break;
}
}
// Consistency test of special values:
samples = new long[]
{
0,
long.MinValue, -1000000000000000000, -999999999999999999, -100000000000000000, -99999999999999999, -10000000000000000, -9999999999999999, -1000000000000000, -999999999999999, -100000000000000, -99999999999999, -10000000000000, -9999999999999, -1000000000000, -999999999999, -100000000000, -99999999999, -10000000000, -9999999999, -1000000000, -999999999, -100000000, -99999999, -10000000, -9999999, -1000000, -999999, -100000, -99999, -10000, -9999, -1000, -999, -100, -99, -10, -9, - 1,
long.MaxValue, 1000000000000000000, 999999999999999999, 100000000000000000, 99999999999999999, 10000000000000000, 9999999999999999, 1000000000000000, 999999999999999, 100000000000000, 99999999999999, 10000000000000, 9999999999999, 1000000000000, 999999999999, 100000000000, 99999999999, 10000000000, 9999999999, 1000000000, 999999999, 100000000, 99999999, 10000000, 9999999, 1000000, 999999, 100000, 99999, 10000, 9999, 1000, 999, 100, 99, 10, 9, 1,
};
for (int i = 0; i < samples.Length; ++i)
{
long s = samples[i];
int a = s.Digits_IfChain();
int b = s.Digits_Log10();
int c = s.Digits_While();
int d = s.Digits_String();
if (a != b || c != d || a != c)
{
Console.WriteLine($"Digits({s}): IfChain={a} Log10={b} While={c} String={d}");
isConsistent = false;
break;
}
}
// Consistency test result:
if (isConsistent)
Console.WriteLine("Consistency tests are OK");
}
}
}
답변
직접 C #은 아니지만 공식은 다음과 같습니다. n = floor(log10(x)+1)
답변
이미 여기에있는 답변은 부호없는 정수에 대해 작동하지만 소수와 두 배에서 자릿수를 얻는 좋은 솔루션을 찾지 못했습니다.
public static int Length(double number)
{
number = Math.Abs(number);
int length = 1;
while ((number /= 10) >= 1)
length++;
return length;
}
//number of digits in 0 = 1,
//number of digits in 22.1 = 2,
//number of digits in -23 = 2
정밀도가 중요한 경우 입력 유형을에서 double
로 변경할 수 decimal
있지만 십진수도 제한이 있습니다.
답변
Steve 의 대답 은 맞지만 1보다 작은 정수에서는 작동하지 않습니다.
다음은 네거티브에 대해 작동하는 업데이트 된 버전입니다.
int digits = n == 0 ? 1 : Math.Floor(Math.Log10(Math.Abs(n)) + 1)
답변
재귀 사용 (간혹 인터뷰에서 요청 됨)
public int CountDigits(int number)
{
// In case of negative numbers
number = Math.Abs(number);
if (number >= 10)
return CountDigits(number / 10) + 1;
return 1;
}
