int (C #)의 첫 번째 숫자를 어떻게 얻을 수 있습니까?
C #에서 int의 첫 번째 숫자를 얻는 가장 좋은 방법은 무엇입니까? 내가 생각 해낸 방법은 int를 문자열로 바꾸고 문자열의 첫 번째 문자를 찾은 다음 다시 int로 바꾸는 것입니다.
int start = Convert.ToInt32(curr.ToString().Substring(0, 1));
이것이 작업을 수행하는 동안 아마도 그러한 문제에 대한 훌륭하고 간단한 수학 기반 솔루션이있는 것처럼 느껴집니다. 문자열 조작이 어색해집니다.
편집 : 속도 차이에 관계없이 Substring () 대신 mystring [0]은 여전히 문자열 조작입니다.
방법은 다음과 같습니다.
int i = Math.Abs(386792);
while(i >= 10)
i /= 10;
그리고 i
당신이 필요로 포함됩니다
벤치 마크
첫째, 알고리즘의 효율성, 가독성 / 유지 보수성 및 향후 버그 발생 가능성을 고려하여 "최상의"솔루션이 의미하는 바를 결정해야합니다. 그러나 신중한 단위 테스트는 일반적으로 이러한 문제를 피할 수 있습니다.
이 예제를 각각 천만 번 실행했으며 결과 값은 ElapsedTicks
통과 한 수입니다.
더 이상 고민하지 않고 가장 느린 것부터 가장 빠른 것까지 알고리즘은 다음과 같습니다.
문자열로 변환, 첫 번째 문자 가져 오기
int firstDigit = (int)(Value.ToString()[0]) - 48;
결과 :
12,552,893 ticks
로그 사용
int firstDigit = (int)(Value / Math.Pow(10, (int)Math.Floor(Math.Log10(Value))));
결과 :
9,165,089 ticks
루핑
while (number >= 10)
number /= 10;
결과 :
6,001,570 ticks
조건부
int firstdigit;
if (Value < 10)
firstdigit = Value;
else if (Value < 100)
firstdigit = Value / 10;
else if (Value < 1000)
firstdigit = Value / 100;
else if (Value < 10000)
firstdigit = Value / 1000;
else if (Value < 100000)
firstdigit = Value / 10000;
else if (Value < 1000000)
firstdigit = Value / 100000;
else if (Value < 10000000)
firstdigit = Value / 1000000;
else if (Value < 100000000)
firstdigit = Value / 10000000;
else if (Value < 1000000000)
firstdigit = Value / 100000000;
else
firstdigit = Value / 1000000000;
결과 :
1,421,659 ticks
펼쳐지고 최적화 된 루프
if (i >= 100000000) i /= 100000000;
if (i >= 10000) i /= 10000;
if (i >= 100) i /= 100;
if (i >= 10) i /= 10;
결과 :
1,399,788 ticks
노트 :
Random.Next()
다음을 얻기 위해 각 테스트 호출int
이 시도
public int GetFirstDigit(int number) {
if ( number < 10 ) {
return number;
}
return GetFirstDigit ( (number - (number % 10)) / 10);
}
편집하다
여러 사람이 루프 버전을 요청했습니다.
public static int GetFirstDigitLoop(int number)
{
while (number >= 10)
{
number = (number - (number % 10)) / 10;
}
return number;
}
내가 생각 해낼 수있는 최선의 방법은 다음과 같습니다.
int numberOfDigits = Convert.ToInt32(Math.Floor( Math.Log10( value ) ) );
int firstDigit = value / Math.Pow( 10, numberOfDigits );
...
별로 예쁘지 않다 :)
[편집 됨 : 첫 번째 답변은 정말 나빴습니다. :)]
[편집 2 : 나는 아마도 문자열 조작 솔루션을 조언 할 것입니다.]
[편집 3 : 코드 서식 이 좋습니다. :)]
Anton의 대답에 대한 변형 :
// cut down the number of divisions (assuming i is positive & 32 bits)
if (i >= 100000000) i /= 100000000;
if (i >= 10000) i /= 10000;
if (i >= 100) i /= 100;
if (i >= 10) i /= 10;
Lennaert와 같은 아이디어를 가졌습니다.
int start = number == 0 ? 0 : number / (int) Math.Pow(10,Math.Floor(Math.Log10(Math.Abs(number))));
이것은 음수에서도 작동합니다.
Keltex의 대답이 추악하다고 생각한다면 이것을 시도하십시오. 정말 추하고 더 빠릅니다. 길이를 결정하기 위해 펼쳐진 이진 검색을 수행합니다.
... leading code along the same lines
/* i<10000 */
if (i >= 100){
if (i >= 1000){
return i/1000;
}
else /* i<1000 */{
return i/100;
}
}
else /* i<100*/ {
if (i >= 10){
return i/10;
}
else /* i<10 */{
return i;
}
}
PS MartinStettner도 같은 생각을했습니다.
int myNumber = 8383;
char firstDigit = myNumber.ToString()[0];
// char = '8'
분명하지만 느린 수학적 접근 방식은 다음과 같습니다.
int firstDigit = (int)(i / Math.Pow(10, (int)Math.Log10(i))));
int temp = i;
while (temp >= 10)
{
temp /= 10;
}
의 결과 temp
나는 그것이 C #이 아니라는 것을 알고 있지만, 파이썬에서 "숫자의 문자열 표현의 첫 번째 문자를 얻는다"가 더 빠르다는 것은 놀랍습니다!
편집 : 아니요, 실수를 저질렀습니다. int를 다시 구성하는 것을 잊었습니다. 죄송합니다. 펼쳐진 버전은 가장 빠릅니다.
$ cat first_digit.py
def loop(n):
while n >= 10:
n /= 10
return n
def unrolled(n):
while n >= 100000000: # yea... unlimited size int supported :)
n /= 100000000
if n >= 10000:
n /= 10000
if n >= 100:
n /= 100
if n >= 10:
n /= 10
return n
def string(n):
return int(str(n)[0])
$ python -mtimeit -s 'from first_digit import loop as test' \
'for n in xrange(0, 100000000, 1000): test(n)'
10 loops, best of 3: 275 msec per loop
$ python -mtimeit -s 'from first_digit import unrolled as test' \
'for n in xrange(0, 100000000, 1000): test(n)'
10 loops, best of 3: 149 msec per loop
$ python -mtimeit -s 'from first_digit import string as test' \
'for n in xrange(0, 100000000, 1000): test(n)'
10 loops, best of 3: 284 msec per loop
$
나는 방금이 오래된 질문을 우연히 발견하고 지금까지 다른 답변 중 어느 것도 가능한 모든 입력 값에 대해 올바른 결과를 반환하지 않았고 여전히 더 빠르게 만들 수 있기 때문에 다른 제안을 제안하려는 경향이 있다고 느꼈습니다 .
public static int GetFirstDigit( int i )
{
if( i < 0 && ( i = -i ) < 0 ) return 2;
return ( i < 100 ) ? ( i < 1 ) ? 0 : ( i < 10 )
? i : i / 10 : ( i < 1000000 ) ? ( i < 10000 )
? ( i < 1000 ) ? i / 100 : i / 1000 : ( i < 100000 )
? i / 10000 : i / 100000 : ( i < 100000000 )
? ( i < 10000000 ) ? i / 1000000 : i / 10000000
: ( i < 1000000000 ) ? i / 100000000 : i / 1000000000;
}
이것은 -2147483648
가장 작은 부호있는 정수이고 양의 대응 값이없는 모든 부호있는 정수 값에 대해 작동합니다 . Math.Abs( -2147483648 )
트리거 System.OverflowException
및 - -2147483648
계산합니다을 -2147483648
.
구현은 지금까지 가장 빠른 두 구현의 장점을 결합한 것으로 볼 수 있습니다. 이진 검색을 사용하고 불필요한 분할을 방지합니다. 100,000,000 번의 반복이있는 루프 인덱스를 사용한 빠른 벤치 마크는 현재 가장 빠른 구현보다 두 배 빠르다는 것을 보여줍니다.
2,829,581 틱 후에 완료 됩니다.
비교를 위해 5,664,627 틱 이 걸린 현재 가장 빠른 구현의 수정 된 변형도 측정했습니다 .
public static int GetFirstDigitX( int i )
{
if( i < 0 && ( i = -i ) < 0 ) return 2;
if( i >= 100000000 ) i /= 100000000;
if( i >= 10000 ) i /= 10000;
if( i >= 100 ) i /= 100;
if( i >= 10 ) i /= 10;
return i;
}
내 컴퓨터에서이 테스트를 위해 동일한 수정으로 받아 들여진 답변에는 16,561,929 틱이 필요 했습니다 .
public static int GetFirstDigitY( int i )
{
if( i < 0 && ( i = -i ) < 0 ) return 2;
while( i >= 10 )
i /= 10;
return i;
}
현재 하드웨어에서 가능한 모든 정수 값을 반복하는 데 몇 초도 걸리지 않기 때문에 이와 같은 간단한 함수는 정확성을 쉽게 입증 할 수 있습니다. 이것은 나중에 버그를 수정할 필요가 없기 때문에 예외적으로 읽기 쉬운 방식으로 구현하는 것이 덜 중요하다는 것을 의미합니다.
매우 간단합니다 (비교와 하나의 분할 만 포함하므로 매우 빠름).
if(i<10)
firstdigit = i;
else if (i<100)
firstdigit = i/10;
else if (i<1000)
firstdigit = i/100;
else if (i<10000)
firstdigit = i/1000;
else if (i<100000)
firstdigit = i/10000;
else (etc... all the way up to 1000000000)
여기 동료 중 한 명과 몇 가지 테스트를 수행 한 결과 대부분의 솔루션이 0 미만의 숫자에 대해 작동하지 않는다는 것을 알았습니다.
public int GetFirstDigit(int number)
{
number = Math.Abs(number); <- makes sure you really get the digit!
if (number < 10)
{
return number;
}
return GetFirstDigit((number - (number % 10)) / 10);
}
아래의 모든 예제를 사용하여이 코드를 얻습니다.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace Benfords
{
class Program
{
static int FirstDigit1(int value)
{
return Convert.ToInt32(value.ToString().Substring(0, 1));
}
static int FirstDigit2(int value)
{
while (value >= 10) value /= 10;
return value;
}
static int FirstDigit3(int value)
{
return (int)(value.ToString()[0]) - 48;
}
static int FirstDigit4(int value)
{
return (int)(value / Math.Pow(10, (int)Math.Floor(Math.Log10(value))));
}
static int FirstDigit5(int value)
{
if (value < 10) return value;
if (value < 100) return value / 10;
if (value < 1000) return value / 100;
if (value < 10000) return value / 1000;
if (value < 100000) return value / 10000;
if (value < 1000000) return value / 100000;
if (value < 10000000) return value / 1000000;
if (value < 100000000) return value / 10000000;
if (value < 1000000000) return value / 100000000;
return value / 1000000000;
}
static int FirstDigit6(int value)
{
if (value >= 100000000) value /= 100000000;
if (value >= 10000) value /= 10000;
if (value >= 100) value /= 100;
if (value >= 10) value /= 10;
return value;
}
const int mcTests = 1000000;
static void Main(string[] args)
{
Stopwatch lswWatch = new Stopwatch();
Random lrRandom = new Random();
int liCounter;
lswWatch.Start();
for (liCounter = 0; liCounter < mcTests; liCounter++)
FirstDigit1(lrRandom.Next());
lswWatch.Stop();
Console.WriteLine("Test {0} = {1} ticks", 1, lswWatch.ElapsedTicks);
lswWatch.Reset();
lswWatch.Start();
for (liCounter = 0; liCounter < mcTests; liCounter++)
FirstDigit2(lrRandom.Next());
lswWatch.Stop();
Console.WriteLine("Test {0} = {1} ticks", 2, lswWatch.ElapsedTicks);
lswWatch.Reset();
lswWatch.Start();
for (liCounter = 0; liCounter < mcTests; liCounter++)
FirstDigit3(lrRandom.Next());
lswWatch.Stop();
Console.WriteLine("Test {0} = {1} ticks", 3, lswWatch.ElapsedTicks);
lswWatch.Reset();
lswWatch.Start();
for (liCounter = 0; liCounter < mcTests; liCounter++)
FirstDigit4(lrRandom.Next());
lswWatch.Stop();
Console.WriteLine("Test {0} = {1} ticks", 4, lswWatch.ElapsedTicks);
lswWatch.Reset();
lswWatch.Start();
for (liCounter = 0; liCounter < mcTests; liCounter++)
FirstDigit5(lrRandom.Next());
lswWatch.Stop();
Console.WriteLine("Test {0} = {1} ticks", 5, lswWatch.ElapsedTicks);
lswWatch.Reset();
lswWatch.Start();
for (liCounter = 0; liCounter < mcTests; liCounter++)
FirstDigit6(lrRandom.Next());
lswWatch.Stop();
Console.WriteLine("Test {0} = {1} ticks", 6, lswWatch.ElapsedTicks);
Console.ReadLine();
}
}
}
AMD Ahtlon 64 X2 Dual Core 4200+ (2.2GHz)에서 다음과 같은 결과를 얻었습니다.
Test 1 = 2352048 ticks
Test 2 = 614550 ticks
Test 3 = 1354784 ticks
Test 4 = 844519 ticks
Test 5 = 150021 ticks
Test 6 = 192303 ticks
하지만 AMD FX 8350 Eight Core (4.00GHz)에서 얻을 수 있습니다.
Test 1 = 3917354 ticks
Test 2 = 811727 ticks
Test 3 = 2187388 ticks
Test 4 = 1790292 ticks
Test 5 = 241150 ticks
Test 6 = 227738 ticks
따라서 방법 5 또는 6이 더 빠른지 여부는 CPU에 따라 다르지만 CPU 명령 프로세서의 분기 예측이 새 프로세서에서 더 똑똑하기 때문이라고 추측 할 수 있지만 확실하지는 않습니다.
인텔 CPU가 없습니다. 누군가가 우리를 위해 테스트 할 수 있습니까?
이것도 확인하십시오.
int get1digit(Int64 myVal)
{
string q12 = myVal.ToString()[0].ToString();
int i = int.Parse(q12);
return i;
}
여러 숫자를 원하는 경우에도 좋습니다.
int get3digit(Int64 myVal) //Int64 or whatever numerical data you have
{
char mg1 = myVal.ToString()[0];
char mg2 = myVal.ToString()[1];
char mg3 = myVal.ToString()[2];
char[] chars = { mg1, mg2, mg3 };
string q12= new string(chars);
int i = int.Parse(q12);
return i;
}
while (i > 10)
{
i = (Int32)Math.Floor((Decimal)i / 10);
}
// i is now the first int
비 반복 공식 :
public static int GetHighestDigit(int num)
{
if (num <= 0)
return 0;
return (int)((double)num / Math.Pow(10f, Math.Floor(Math.Log10(num))));
}
대안을 제공하기 위해 정수를 10으로 반복적으로 나눈 다음 0에 도달하면 하나의 값을 롤백 할 수 있습니다. 문자열 작업은 일반적으로 느리기 때문에 문자열 조작보다 빠를 수 있지만 결코 우아하지는 않습니다.
이 같은:
while(curr>=10)
curr /= 10;
start = getFirstDigit(start);
public int getFirstDigit(final int start){
int number = Math.abs(start);
while(number > 10){
number /= 10;
}
return number;
}
또는
public int getFirstDigit(final int start){
return getFirstDigit(Math.abs(start), true);
}
private int getFirstDigit(final int start, final boolean recurse){
if(start < 10){
return start;
}
return getFirstDigit(start / 10, recurse);
}
int start = curr;
while (start >= 10)
start /= 10;
This is more efficient than a ToString() approach which internally must implement a similar loop and has to construct (and parse) a string object on the way ...
Very easy method to get the Last digit:
int myInt = 1821;
int lastDigit = myInt - ((myInt/10)*10); // 1821 - 1820 = 1
This is what I usually do ,please refer my function below :
This function can extract first number occurance from any string you can modify and use this function according to your usage
public static int GetFirstNumber(this string strInsput)
{
int number = 0;
string strNumber = "";
bool bIsContNo = true;
bool bNoOccued = false;
try
{
var arry = strInsput.ToCharArray(0, strInsput.Length - 1);
foreach (char item in arry)
{
if (char.IsNumber(item))
{
strNumber = strNumber + item.ToString();
bIsContNo = true;
bNoOccued = true;
}
else
{
bIsContNo = false;
}
if (bNoOccued && !bIsContNo)
{
break;
}
}
number = Convert.ToInt32(strNumber);
}
catch (Exception ex)
{
return 0;
}
return number;
}
Here is a simpler way that does not involve looping
int number = 1234
int firstDigit = Math.Floor(number/(Math.Pow(10, number.ToString().length - 1))
That would give us 1234/Math.Pow(10, 4 - 1) = 1234/1000 = 1
int i = 4567789;
int digit1 = int.Parse(i.ToString()[0].ToString());
참고URL : https://stackoverflow.com/questions/701322/how-can-you-get-the-first-digit-in-an-int-c
'Programing' 카테고리의 다른 글
왼쪽 상단이 둥근 모서리와 왼쪽 하단이 둥근 모서리로 모양을 만드는 방법은 무엇입니까? (0) | 2020.10.14 |
---|---|
JSLint 오류 : 모든 'var'선언을 함수의 맨 위로 이동 (0) | 2020.10.14 |
nodejs에서 node-sass를 사용할 때 libsass 바인딩을 찾을 수 없습니다. (0) | 2020.10.13 |
C99에서 가장 유용한 새 기능은 무엇입니까? (0) | 2020.10.13 |
JavaScript와 Java의 차이점은 무엇입니까? (0) | 2020.10.13 |