Programing

int (C #)의 첫 번째 숫자를 어떻게 얻을 수 있습니까?

crosscheck 2020. 10. 13. 07:26
반응형

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

반응형