정수가 짝수인지 홀수인지 어떻게 확인합니까? [닫은]


193

C에서 주어진 숫자가 짝수인지 홀수인지 어떻게 확인할 수 있습니까?


5
비트 단위 (&)를 사용하는 버전은 모듈로 (%) 버전보다 훨씬 효율적입니다. 정답으로 선택한 것을 변경해야합니다.
Stefan Rusek

6
중요하지는 않지만 인수는 상수입니다. 최적화를위한 쉬운
MSalters

2
가독성 또한 이것에 영향을 미칩니다.
Brian G

2
임베디드 응용 프로그램 (내 프로그래밍 시간의 대부분을 소비하는 세계)에서 일부 프로세서는 매우 원시적 인 산술 단위를 가지며 나누기 / 모듈러스 연산을 쉽게 수행 할 수 없습니다. 이러한 이유로 나는 보통 비트 단위 방식을 사용합니다. 그러나 최신 데스크톱의 CPU에서는 그렇지 않습니다.
bta

3
모듈러스 연산이 이해하기 쉬운 것을 찾지 못했습니다. 처음에 짝수 또는 홀수를 결정해야 할 때 비트 마스크가 가장 먼저 떠 올랐습니다. 우리가 손으로이 작업을하는 방식은 {0 2 4 6 8} 또는 {1 3 5 7 9}에 있는지 확인하기 위해 가장 중요하지 않은 숫자를 보는 것이므로 다소 자연 스럽습니다. 이는 0 또는 1인지 확인하기 위해 최하위 비트를 직접 보는 것으로 변환됩니다.
P Daddy

답변:


449

모듈로 (%) 연산자를 사용하여 2로 나눌 때 나머지가 있는지 확인하십시오.

if (x % 2) { /* x is odd */ }

몇몇 사람들은 x & 1을 사용하는 것이 "더 빠르다"거나 "보다 효율적"이라는 내 대답을 비판했습니다. 나는 이것이 사실이라고 생각하지 않습니다.

호기심으로 두 가지 사소한 테스트 사례 프로그램을 만들었습니다.

/* modulo.c */
#include <stdio.h>

int main(void)
{
    int x;
    for (x = 0; x < 10; x++)
        if (x % 2)
            printf("%d is odd\n", x);
    return 0;
}

/* and.c */
#include <stdio.h>

int main(void)
{
    int x;
    for (x = 0; x < 10; x++)
        if (x & 1)
            printf("%d is odd\n", x);
    return 0;
}

그런 다음 내 컴퓨터 중 하나에서 5 번 다른 시간에 gcc 4.1.3으로 컴파일했습니다.

  • 최적화 플래그가 없습니다.
  • -O로
  • -O로
  • -O2로
  • -O3 사용

각 컴파일 (gcc -S 사용)의 어셈블리 출력을 조사한 결과 각 경우에 and.c와 modulo.c의 출력이 동일하다는 것을 알았습니다 (둘 다 andl $ 1, % eax 명령을 사용했습니다). 나는 이것이 "새로운"기능이라고 의심하고, 그것이 고대 버전으로 거슬러 올라간다고 생각한다. 또한 상업용 또는 오픈 소스와 같은 현대 (비록 20 년 동안 만들어진) 비-아칸 컴파일러가 그러한 최적화가 부족한 것으로 의심합니다. 다른 컴파일러에서 테스트하려고하지만 현재 사용할 수있는 제품이 없습니다.

다른 누군가가 다른 컴파일러 및 / 또는 플랫폼 대상을 테스트하고 다른 결과를 얻으려면 매우 관심이 있습니다.

마지막으로 모듈로 버전은 구현에서 부호있는 정수의 표현에 관계없이 정수가 양수인지, 음수인지 또는 0인지를 표준으로 보장 합니다. 비트 및 버전이 아닙니다. 예, 2의 보수가 어느 곳에서나 유비쿼터스라는 것을 알고 있습니다.


11
질문은 구체적으로 C로 수행하는 방법을 묻었으므로 chustar는 Java로 수행하는 방법을 해결할 수 없다는 언급에도 불구하고 C로 대답했습니다. 나는 이것이 자바 답변이라고 주장하거나 암시하지 않았다. 나는 Java를 모른다. 방금 첫 번째 downvote를 받았으며 그 이유에 대해 혼란스러워합니다. 오 잘
Chris Young

33
만약 (x % 2! = 0) {/ * x가 홀수 * /}라면 누가 알겠습니까? 자바도 모른다.
eugensk

9
우리의 업장을 표명하지 않고 비트 연산자 모르 론과 구별하기 위해 많은 공감대를 얻고 있습니다.
wnoise

13
나는 한 가지를 제외하고 모든 것에 동의합니다. 정수와 진리 값을 개념적으로 분리하여 유지하는 것을 좋아하므로 "if (x % 2 == 1)"를 쓰는 것을 선호합니다. 컴파일러와 동일하지만 인간에게는 조금 더 명확합니다. 또한 0이 아닌 것으로 해석하지 않는 언어에서 동일한 코드를 사용할 수 있습니다.
Thomas Padron-McCarthy

46
내 벤치 마크? 어떤 벤치 마크? 벤치마킹을하지 않았습니다. 생성 된 어셈블리 언어를 조사했습니다. 이것은 printf와 전혀 관련이 없습니다.
Chris Young

207

너희들은 너무 효율적이다. 당신이 정말로 원하는 것은 :

public boolean isOdd(int num) {
  int i = 0;
  boolean odd = false;

  while (i != num) {
    odd = !odd;
    i = i + 1;
  }

  return odd;
}

에 대해 반복하십시오 isEven.

물론 음수에는 작동하지 않습니다. 그러나 광채로 희생이 온다 ...


17
음수 값에 대해 인수 예외를 발생시키고 설명서 에서이 함수가 O (N)임을 언급하면 ​​이것으로 좋을 것입니다.
Jeffrey L Whitledge

7
엔터프라이즈 버전은 XML을 사용해야합니다. 물론 요즘에는 웹 서비스를 통해 쿼리를 할 수 있습니다.
Martin Beckett

58
조회 테이블을 사용하여이를 최적화해야합니다.
Weeble

1
나는 새로운 천년에 한하여 6999 담당자로했다, 그런 수도사 해요
에 란 메단을

7
훌륭합니다! 상사는 자신의 Enterprise License가 Standard License 이상을 제공하지 않는다고 생각하여 화가 났다고 말했습니다. 이제 우리는 프로그램에이 기능을 추가했으며, 실행 속도가 느리기 때문에 그의 소프트웨어가 더 많은 작업을하고 있다고 생각합니다 !!!
Phil

97

비트 산술을 사용하십시오.

if((x & 1) == 0)
    printf("EVEN!\n");
else
    printf("ODD!\n");

분할 또는 계수를 사용하는 것보다 빠릅니다.


43
분할 또는 모듈러스를 사용하는 것보다 빠르다고 말하는 것이 공정하지 않다고 생각합니다. C 표준은 연산자의 성능에 대해 아무 말도하지 않으며 적절한 컴파일러는 빠른 코드를 생성합니다. 나는 개인적으로 나의 의도를 전달하는 관용구를 선택하고 여기에 %가 더 적절 해 보인다
Chris Young

21
숫자가 사람들과 같은 방식인지 확인하기 때문에 (x & 1)이 더 좋습니다. 마지막 숫자가 짝수인지 홀수인지 확인하십시오. 내 생각에 그것은 모듈로 방법보다 그 의도를 전달합니다. (별로 중요하지 않습니다.)
Jeremy Ruten

2
네 말이 맞아 주관적인 것 같아 "even"의 일반적인 정의는 "0, 2, 4, 6 또는 8로 끝나는 정수"가 아니라 "2로 나눌 수있는 정수"입니다. :-)
Chris Young

4
@TraumaPony-ANSI 표준 C 및 초기 Java의 경우 컴퓨터 시스템에 따라 다릅니다. 부호가있는 숫자 (2의 칭찬, 1의 칭찬, 회색 코딩 등)에 어떤 표현이 사용되는지는 불분명합니다. 그러나 계수는 항상 계수입니다
Aaron

9
음수에는 보편적으로 작동하지 않습니다. 자세한 내용이 대답을 확인을 참조하십시오 : stackoverflow.com/questions/160930/... 자세한 내용은.
Andrew Edgecombe

36

[Joke mode = "on"]

public enum Evenness
{
  Unknown = 0,
  Even = 1,
  Odd = 2
}

public static Evenness AnalyzeEvenness(object o)
{

  if (o == null)
    return Evenness.Unknown;

  string foo = o.ToString();

  if (String.IsNullOrEmpty(foo))
    return Evenness.Unknown;

  char bar = foo[foo.Length - 1];

  switch (bar)
  {
     case '0':
     case '2':
     case '4':
     case '6':
     case '8':
       return Evenness.Even;
     case '1':
     case '3':
     case '5':
     case '7':
     case '9':
       return Evenness.Odd;
     default:
       return Evenness.Unknown;
  }
}

[조크 모드 = "끄기"]

편집 : 열거 형에 혼란스러운 값을 추가했습니다.


2
와우 ... 이것은 SCdF의 솔루션보다 더 치밀합니다! 명성! 추천하지는 않지만 ... 권장 할 수 없습니다. 그러나 재밌습니다!
Wes P

1
이 방법의 장점은 단순한 숫자 이상으로 작동한다는 것입니다. 또한이 줄을 바꾸면 : char bar = foo [foo.Length-1]; 이것으로 : double bar = Char.GetNumericValue (foo [foo.Length-1]); 그런 다음 모든 숫자 시스템에서 작동합니다.
Jeffrey L Whitledge

5
버그 보고서 : 14.65는 알 수없는 경우 홀수로보고됩니다.
TheSoftwareJedi

4
소프트웨어 Jedi는 "기능"입니다. ;)
Sklivvz

31
The SoftwareJedi : 14.65는 내가 본 것 중 가장 이상한 정수 중 하나입니다.
Bruce Alderman 21시 44 분

16

ffpf에 대한 응답으로 -몇 년 전 동료와 정확히 같은 주장을했으며 대답은 no 이며 음수로는 작동하지 않습니다.

C 표준은 음수를 3 가지 방식으로 표현할 수 있다고 규정합니다.

  • 2의 보수
  • 1의 보수
  • 부호와 크기

다음과 같이 확인하십시오.

isEven = (x & 1);

2의 보수와 부호 및 크기 표현에는 작동하지만 1의 보수에는 작동하지 않습니다.

그러나 모든 경우에 다음이 작동한다고 생각합니다.

isEven = (x & 1) ^ ((-1 & 1) | ((x < 0) ? 0 : 1)));

문자 상자가 문자보다 작을 때 모든 것을 먹었다는 것을 지적한 ffpf에게 감사드립니다!


두 번째 코드 예제에 일부 텍스트가 누락 된 것 같습니다.
Jeff Yates

3
그 숫자를 칭찬합시다!
thejh

14

좋은 것은 :

/*forward declaration, C compiles in one pass*/
bool isOdd(unsigned int n);

bool isEven(unsigned int n)
{
  if (n == 0) 
    return true ;  // I know 0 is even
  else
    return isOdd(n-1) ; // n is even if n-1 is odd
}

bool isOdd(unsigned int n)
{
  if (n == 0)
    return false ;
  else
    return isEven(n-1) ; // n is odd if n-1 is even
}

이 방법은 두 가지 기능이 포함 된 테일 재귀를 사용합니다. 컴파일러가 Scheme 컴파일러와 같은 테일 재귀를 지원하면 효율적으로 구현할 수 있습니다 (while / 루프 유형으로 바 turn). 이 경우 스택이 오버플로되지 않아야합니다!


1
이것은 isOdd (0)를 잘 처리하지 못합니다.
Steve McLeod

1
짝수 값을 가진 isOdd () 또는 홀수 값을 가진 isEven ()에 대해 무한 루프 (꼬리 재귀 포함) 또는 스택 오버플로 (꼬리 재귀 제외)가 있다고 생각합니다. true로만 종료됩니다. 다시 한 번 멈추는 문제입니다.
Jeffrey L Whitledge

7
아, 물론, 의견없이 고쳐서 바보처럼 보이게하십시오. 괜찮아.
Jeffrey L Whitledge

1
이제 컴파일 오류가 있습니다. isE에서도 모든 코드 경로가 값을 반환하는 것은 아닙니다. 아니요, 실제로이 코드를 시도하지 않았습니다. 고소하는 것은 컴파일러입니다.
Jeffrey L Whitledge

5
컴파일 오류 : 모든 경로가 샘플 코드에 대한 버그 주석으로 폭격하기를 싫어하는 값을 반환하는 것은 아니지만 isEven (5)
Kevin

11

2로 나눌 때 나머지가 0 인 경우에도 숫자는 짝수입니다. 2로 나눌 때 나머지가 1이면 숫자는 홀수입니다.

// Java
public static boolean isOdd(int num){
    return num % 2 != 0;
}

/* C */
int isOdd(int num){
    return num % 2;
}

방법은 훌륭합니다!


음수 홀수에 대해 num % 2 == -1 때문에 Java 메소드가 중단되었습니다.
WMR

그게 왜 저를 다운 보트 했습니까?
jjnguy

3
C의 함수가 수행하는 것보다 입력하는 데 더 많은 문자가 필요하기 때문에 하향 조정했습니다. IE num % I은 공백을 포함하여 7 자이며 IsOdd (I)는 8 자입니다. 왜 단순히 작업을 수행하는 것보다 긴 함수를 작성 하시겠습니까?
Kevin

13
내 의견 코드의 @Kevin은 문자로 측정되는 것이 아니라 think + 디버그 시간을 포함하여 코드를 작성하는 데 걸리는 시간입니다. num % 2는 isOdd보다 생각하는 데 밀리 초가 더 걸립니다. 이제 전 세계적으로 숫자를 추가하면 단체 연도를 잃어 버렸습니다. 또한 isOdd는 테스트를 거쳐 검증되고 결국 버그가없는 인증을받습니다 (예 : 음수 처리). 숫자 % 2-일부 개발자는 항상 의심을 가지고 실험을합니다. 좋은 코드는 작성하지 않고 재사용 만하는 코드입니다. 단지 2 센트입니다.
Eran Medan

2
@EranMedan, i ++를 IncrementByOne (i)으로 바꾸는 데 동일한 논리가 적용되며 이는 나쁜 생각입니다. 개발자가 num % 2의 기능에 대해 의문이 있다면 내 코드 근처에있는 사람을 원하지 않습니다.
Kevin


7

그냥 2로 나누고 나머지가 0이면 짝수입니다. 그렇지 않으면 홀수입니다.

모듈러스 (%)를 사용하면이 작업이 쉬워집니다.

예. 4 % 2 = 0이므로 4는 짝수 5 % 2 = 1이므로 5는 홀수


6

문제에 대한 또 하나의 해결책
(어린이들은 투표를 환영합니다)

bool isEven(unsigned int x)
{
  unsigned int half1 = 0, half2 = 0;
  while (x)
  {
     if (x) { half1++; x--; }
     if (x) { half2++; x--; }

  }
  return half1 == half2;
}

아니요, 당신은 내가
의지 한

나는 이것을 공표하려고했지만 음수에서는 조금 느립니다. :)
Chris Young

3
모든 숫자는 밝고 긍정적입니다. 아니면 일부에 대해 편견을 가지고 있습니까? :))
eugensk

3
컴퓨터에서는 모든 숫자가 음수이면 결국 양수가됩니다. 우리는 그것을 행복의 롤오버라고 부릅니다 (BIGNUMS, YMMY에는 적용되지 않으며 일부 주에서는 유효하지 않습니다).
Will Hartung

@WillHartung "행복의 롤오버"가 훌륭합니다! : D
thejh

6

정수의 패리티 (홀수이면 1 일 경우 0)의 테이블을 작성하므로 (검색 : D를 수행 할 수 있음) gcc는 이러한 크기의 배열을 만들 수 없습니다.

typedef unsigned int uint;

char parity_uint [UINT_MAX];
char parity_sint_shifted [((uint) INT_MAX) + ((uint) abs (INT_MIN))];
char* parity_sint = parity_sint_shifted - INT_MIN;

void build_parity_tables () {
    char parity = 0;
    unsigned int ui;
    for (ui = 1; ui <= UINT_MAX; ++ui) {
        parity_uint [ui - 1] = parity;
        parity = !parity;
    }
    parity = 0;
    int si;
    for (si = 1; si <= INT_MAX; ++si) {
        parity_sint [si - 1] = parity;
        parity = !parity;
    }
    parity = 1;
    for (si = -1; si >= INT_MIN; --si) {
        parity_sint [si] = parity;
        parity = !parity;
    }
}

char uparity (unsigned int n) {
    if (n == 0) {
        return 0;
    }
    return parity_uint [n - 1];
}

char sparity (int n) {
    if (n == 0) {
        return 0;
    }
    if (n < 0) {
        ++n;
    }
    return parity_sint [n - 1];
}

대신 짝수와 홀수의 수학적 정의에 의지 해 봅시다.

정수 n은 정수 = k가 존재하더라도 n = 2k이다.

n = 2k + 1과 같은 정수 k가 존재하면 정수 n은 홀수입니다.

코드는 다음과 같습니다.

char even (int n) {
    int k;
    for (k = INT_MIN; k <= INT_MAX; ++k) {
        if (n == 2 * k) {
            return 1;
        }
    }
    return 0;
}

char odd (int n) {
    int k;
    for (k = INT_MIN; k <= INT_MAX; ++k) {
        if (n == 2 * k + 1) {
            return 1;
        }
    }
    return 0;
}

C-integers int가 주어진 C 컴파일에서 가능한 값을 나타냅니다 . C-integers는 정수의 하위 집합입니다.

이제 C-integers에서 주어진 n에 대해 해당 정수 k가 C-integers 내에 존재하지 않을 것이라고 걱정할 수 있습니다. 그러나 약간의 증거만으로도 모든 정수 n, | n | <= | 2n | (*), 여기서 | n | "n이 양수이면 n이고 그렇지 않으면 -n"입니다. 다시 말해, 정수의 모든 n에 대해 다음 중 하나 이상이 사실입니다 (사실 사례 (1 및 2) 또는 사례 (3 및 4)이지만 실제로는 증명하지 않습니다).

사례 1 : n <= 2n.

사례 2 : -n <= -2n.

사례 3 : -n <= 2n.

사례 4 : n <= -2n.

이제 2k = n을 취하십시오. (n은 짝수이면 이러한 ak가 존재하지만 여기서 증명하지는 않습니다. n이 짝 수면 루프 인은 even어쨌든 일찍 반환되지 않으므로 중요하지 않습니다.) 그러나 이것은 n <n이면 k <n을 의미합니다 0으로 (*)가 아니며 모든 m에 대해 정수 2m = z의 z는 m이 0이 아닌 m과 같지 않은 z를 의미합니다. n이 0 인 경우, 2 * 0 = 0 따라서 0도 완료됩니다 (n = 0이면 0은 C 정수에 있습니다 .n은 C 정수에 even있기 때문에 k = 0은 C 정수에 있습니다). 따라서 C-integers의 이러한 ak는 n이 짝수이면 C-integers의 n에 존재합니다.

비슷한 주장은 n이 홀수이면 C-integers에 n = 2k + 1과 같은 ak가 있음을 보여줍니다.

따라서 여기에 제시된 기능 even과 기능 odd은 모든 C-integers에서 올바르게 작동합니다.


1
나는 공격을 의미하지는 않지만이 답변의 요점은 무엇입니까? i % 2훨씬 작고 아마 더 효율적입니다.
GManNickG

2
@ GMan : 그러나 이것은 더 결정 론적입니다! 이것은 모든 경우를 올바르게 감지합니다.
P Daddy

1
... 그리고 (!!!) 맞습니다 !!!
Thomas Eding

당신이 농담하고 있는지 말할 수 없습니다. : X %2는 모든 정수에서 작동합니다.
GManNickG

1
+1 : "좋은 답변"이라고 말하고 싶지만 "흥미로운 답변"이 더 적절하다고 생각합니다.
James Webster

5
// C#
bool isEven = ((i % 2) == 0);

2
뭐? C #이 아닙니다! 순수한 C입니다! :-P
asterite

8
순수한 C #을 만들기 위해 WinForm을 던질 것입니다.
Michael Petrotta

@mateusza : 일반적으로 대문자 또는 C에서 "bool"을 볼 때 a typedef또는 a #define입니다.
David Thornley

2
@mateusza @David Thornley C99의 bool은 표준 기능입니다 ( en.wikipedia.org/wiki/Stdbool.h )
fortran

1
매우 중복 된 괄호에 대해 이야기하십시오.
Thomas Eding

4

다음은 Java 답변입니다.

public static boolean isEven (Integer Number) {
    Pattern number = Pattern.compile("^.*?(?:[02]|8|(?:6|4))$");
    String num = Number.toString(Number);
    Boolean numbr = new Boolean(number.matcher(num).matches());
    return numbr.booleanValue();
}

4

이 시도: return (((a>>1)<<1) == a)

예:

a     =  10101011
-----------------
a>>1 --> 01010101
a<<1 --> 10101010

b     =  10011100
-----------------
b>>1 --> 01001110
b<<1 --> 10011100

이것을 설명해 주시겠습니까? 비트 연산자에 익숙하지 않습니다
Abdul

오른쪽과 왼쪽으로 이동하면 마지막 비트 (가장 오른쪽 비트)가 0이됩니다. 새 숫자가 원래 숫자와 같으면 원래 숫자의 마지막 비트가 0임을 의미합니다. 따라서 짝수입니다. 업데이트 된 답변을 살펴보십시오.
Kiril Aleksandrov

감사합니다, 지금
Abdul

어떤 접근 방식이 더 빠른지 잘 모르겠습니다. 나는 그것들을 벤치마킹하려고하지 않았다.
Kiril Aleksandrov

이것도 가장 중요한 비트를 제로화하지 않습니까? 일부 언어의 부호없는 정수와 대부분의 음수 정수 문제
Troyseph

4

다소 재미있는 토론을 읽은 후, 나는 메인 루프 내에서 홀수 및 짝수를 테스트 한 실제적이고 시간에 민감한 기능을 가지고 있음을 기억했습니다. 다음과 같이 StackOverflow의 다른 곳에 게시 된 정수 전력 함수입니다. 벤치 마크는 매우 놀랍습니다. 적어도이 실제 함수에서는 모듈로가 느리고 상당히 중요합니다. 승자는 모듈로 시간의 67 %를 요구하는 넓은 마진으로 또는 (|) 접근 방식 이며이 페이지의 다른 곳에서는 찾을 수 없습니다.

static dbl  IntPow(dbl st0, int x)  {
    UINT OrMask = UINT_MAX -1;
    dbl  st1=1.0;
    if(0==x) return (dbl)1.0;

    while(1 != x)   {
        if (UINT_MAX == (x|OrMask)) {     //  if LSB is 1...    
        //if(x & 1) {
        //if(x % 2) {
            st1 *= st0;
        }    
        x = x >> 1;  // shift x right 1 bit...  
        st0 *= st0;
    }
    return st1 * st0;
}

3 억 루프의 경우 벤치 마크 타이밍은 다음과 같습니다.

3.962 | 마스크 접근

4.851 & 접근

% 접근법 5.850

이론이나 조립 언어 목록을 생각하는 사람들은 이런 주장을 해결해야하는데 이것은 조심스러운 이야기가되어야합니다. 하늘과 땅에는 철학에서 꿈꾸는 것보다 더 많은 것들이 있습니다.


1
unsigned xx = x >> 1;구현 정의 동작 을 그대로 사용 하는 것이 x < 0좋습니다. 이유 xOrMask종류가 불분명 합니다. while(x)테스트를 사용하여 다시 쓸 수있을 정도로 간단합니다 .
chux-복원 Monica Monica

2
대부분의 컴파일러는 % 2비트 단위를 사용하여 사례 를 컴파일 할만 큼 똑똑해야하기 때문에 이것을 벤치마킹 할 때 사용한 컴파일러가 궁금 합니다 &. 방금 이것을 테스트했으며 결과는 완전히 동일합니다 (VS2015, 릴리스는 x86 및 x64의 모든 최적화로 빌드). 수락 된 답변은 GCC (2008 년에 작성 됨)에 대해서도 언급합니다.
Lou

2
이 게시물의 문제점 은 모든 플랫폼 / 컴파일러 에서 비트 단위 or가 비트 단위 보다 빠를 것이라는 전제가 and거의 없다는 것 입니다. 그런 이상한 플랫폼 / 컴파일러 콤보가 있었더라도 (그리고 벤치 마크를 수행하는 데 사용되는 코드도 게시하지 않았음에도 불구하고) 다른 컴파일러에 따라 동일한 동작을 수행하는 것은 좋지 않은 최적화 베팅입니다. 그래서 내가 쓴 것처럼, 나는 이것이 올바르게 측정되지 않았기 때문에 이것이 어느 플랫폼 / 컴파일러에서 테스트되었는지 궁금 합니다.

2
당신을 거짓말 쟁이라고 부르지 말고 정확하게 측정하지 않았다고 확실하게 주장하십시오. 필요가 내 원래의 코멘트, 아직 트럭 운전사 나에게 전화하지 읽기 : 나는 벤치 마크를 만들고, 결과는 ~ 3 시그마의 확실성 (세 가지 경우 모두에서 완전히 같은 예상 한대로 500.000 각 시험 10 번을 실행 한 후 .000 반복). 실제로 오랜 경력을 쌓은 경력이 있다면 한 걸음 물러서서 주장이 이해되는지 생각한 다음 벤치 마크를 수행하는 데 사용 된 실제 코드를 게시하십시오. 그렇지 않으면 포스트는 내가 측정 한 것의 실수라고 생각합니다.
Lou

1

4

이것은 @RocketRoy 와의 답변 에 대한 후속 조치 이지만 이러한 결과를 비교하려는 사람에게는 유용 할 수 있습니다.

TL; DR 내가 본 바로는이 로이의 접근 방식은 ( (0xFFFFFFFF == (x | 0xFFFFFFFE)) 완전히 최적화되지 x & 1는 AS mod접근하지만, 실제로 실행 시간은 모든 경우에 동일 판명한다.

먼저 컴파일러 탐색기를 사용하여 컴파일 된 출력을 비교했습니다 .

테스트 된 기능 :

int isOdd_mod(unsigned x) {
    return (x % 2);
}

int isOdd_and(unsigned x) {
    return (x & 1);
}

int isOdd_or(unsigned x) {
    return (0xFFFFFFFF == (x | 0xFFFFFFFE));
}   

-O3을 포함한 CLang 3.9.0 :

isOdd_mod(unsigned int):                          # @isOdd_mod(unsigned int)
        and     edi, 1
        mov     eax, edi
        ret

isOdd_and(unsigned int):                          # @isOdd_and(unsigned int)
        and     edi, 1
        mov     eax, edi
        ret

isOdd_or(unsigned int):                           # @isOdd_or(unsigned int)
        and     edi, 1
        mov     eax, edi
        ret

-O3을 사용하는 GCC 6.2 :

isOdd_mod(unsigned int):
        mov     eax, edi
        and     eax, 1
        ret

isOdd_and(unsigned int):
        mov     eax, edi
        and     eax, 1
        ret

isOdd_or(unsigned int):
        or      edi, -2
        xor     eax, eax
        cmp     edi, -1
        sete    al
        ret

CLang에 이르기까지 세 가지 경우 모두 기능적으로 동일하다는 것을 깨달았습니다. 그러나 Roy의 접근 방식은 GCC에서 최적화되지 않으므로 YMMV입니다.

Visual Studio와 비슷합니다. 이 세 가지 기능에 대한 디스 어셈블리 릴리스 x64 (VS2015)를 검사하면 비교 부분이 "mod"및 "and"경우와 같고 Roy의 "or"경우에는 약간 더 큽니다.

// x % 2
test bl,1  
je (some address) 

// x & 1
test bl,1  
je (some address) 

// Roy's bitwise or
mov eax,ebx  
or eax,0FFFFFFFEh  
cmp eax,0FFFFFFFFh  
jne (some address)

그러나 이러한 세 가지 옵션 (일반 모드, 비트 단위 또는 비트 단위)을 비교하기위한 실제 벤치 마크를 실행 한 후에는 결과가 완전히 동일했습니다 (Visual Studio 2005 x86 / x64, 릴리스 빌드, 디버거 없음).

릴리스 어셈블리는 test지침 andmod사례를 사용하지만 Roy의 사례는 cmp eax,0FFFFFFFFh접근 방식을 사용 하지만 크게 풀리고 최적화되어 실제로 차이가 없습니다.

20 회 실행 후 결과 (i7 3610QM, Windows 10 전원 관리 옵션이 고성능으로 설정 됨) :

[테스트 : Plain mod 2] 평균 시간 : 689.29 ms (상대 차이 : + 0.000 %)
[테스트 : 비트 단위 또는] 평균 시간 : 689.63 ms (상대 차이 : + 0.048 %)
[테스트 : 비트 및] 평균 시간 : 687.80 ms (상대 차이 : -0.217 %)

이러한 옵션의 차이는 0.3 % 미만이므로 모든 경우에 어셈블리가 동일하다는 것이 분명합니다.

누군가가 시도하고 싶다면 Windows에서만 테스트해야한다는 경고와 함께 코드가 있습니다 ( 정의 #if LINUX조건을 확인하고 get_time필요한 경우이 답변 에서 가져옵니다 ).

#include <stdio.h>

#if LINUX
#include <sys/time.h>
#include <sys/resource.h>
double get_time()
{
    struct timeval t;
    struct timezone tzp;
    gettimeofday(&t, &tzp);
    return t.tv_sec + t.tv_usec*1e-6;
}
#else
#include <windows.h>
double get_time()
{
    LARGE_INTEGER t, f;
    QueryPerformanceCounter(&t);
    QueryPerformanceFrequency(&f);
    return (double)t.QuadPart / (double)f.QuadPart * 1000.0;
}
#endif

#define NUM_ITERATIONS (1000 * 1000 * 1000)

// using a macro to avoid function call overhead
#define Benchmark(accumulator, name, operation) { \
    double startTime = get_time(); \
    double dummySum = 0.0, elapsed; \
    int x; \
    for (x = 0; x < NUM_ITERATIONS; x++) { \
        if (operation) dummySum += x; \
    } \
    elapsed = get_time() - startTime; \
    accumulator += elapsed; \
    if (dummySum > 2000) \
        printf("[Test: %-12s] %0.2f ms\r\n", name, elapsed); \
}

void DumpAverage(char *test, double totalTime, double reference)
{
    printf("[Test: %-12s] AVERAGE TIME: %0.2f ms (Relative diff.: %+6.3f%%)\r\n",
        test, totalTime, (totalTime - reference) / reference * 100.0);
}

int main(void)
{
    int repeats = 20;
    double runningTimes[3] = { 0 };
    int k;

    for (k = 0; k < repeats; k++) {
        printf("Run %d of %d...\r\n", k + 1, repeats);
        Benchmark(runningTimes[0], "Plain mod 2", (x % 2));
        Benchmark(runningTimes[1], "Bitwise or", (0xFFFFFFFF == (x | 0xFFFFFFFE)));
        Benchmark(runningTimes[2], "Bitwise and", (x & 1));
    }

    {
        double reference = runningTimes[0] / repeats;
        printf("\r\n");
        DumpAverage("Plain mod 2", runningTimes[0] / repeats, reference);
        DumpAverage("Bitwise or", runningTimes[1] / repeats, reference);
        DumpAverage("Bitwise and", runningTimes[2] / repeats, reference);
    }

    getchar();

    return 0;
}

나는 당신이 추기경 죄를 저질렀다고 믿는다. 특정 환경을 만들면 실제 환경을 나타내지 않습니다. 어셈블리 언어를보고 사용중인 레지스터 수를 확인하십시오. 노력에 대한 높은 점수이지만 이러한 결과는 실제 처리에서 유지되지 않습니다.

@RocketRoy : 모든 출력이 세 경우 모두에 대해 정확히 동일하기 때문에 (한 경우 프로그램의 경우 약간 더 나 빠짐) 실제로 사용 된 레지스터 수는 중요하지 않습니다. 그러나 다시 한 번 예제와 같은 예제 프로그램 / 환경을 작성하여 게시하면 컴파일러가 혼란스러워 한 경우에 더 최적화 된 어셈블리를 작성하게되며 다른 모든 것은 동일합니다.
Lou

나는 항상 건방진 프로그래머를 좋아합니다. 프로그래머에게는 좋은 특성이지만,보다 복잡한 실제 프로그램에서는 컴파일러가 문제를 해결하는 방법이 더 많아서 명령어가 겹치므로 (Intel 아키텍처에서) 더 나은 결과를 얻을 수 있기 때문에 내 방법은 사용자보다 더 잘 수행됩니다. . 우수한 벤치마킹 경험을 가진 베테랑 프로그래머는 벤치 마크를 선호하지만 좋은 결과를 유지하고 새로운 칩이 출시 될 때 벤치 마크를 다시 실행하는 것을 잊지 마십시오. 시간이지나면서 상황이 변합니다.

3

나는 이것이 구문 설탕이며 .net에서만 적용 할 수 있지만 확장 방법은 어떻 습니까 ?

public static class RudiGroblerExtensions
{
    public static bool IsOdd(this int i)
    {
        return ((i % 2) != 0);
    }
}

이제 다음을 할 수 있습니다

int i = 5;
if (i.IsOdd())
{
    // Do something...
}

1
좋은 코드입니다. 2가 홀수이고 3이 아니라고 주장하는 것이 유감입니다.
Anthony

죄송합니다. 죄송합니다 ... 논리가 잘못 진행되었습니다.
rudigrobler

3

"창의적이지만 혼란스러운 카테고리"에서 나는 다음을 제공합니다.

int isOdd(int n) { return n ^ n * n ? isOdd(n * n) : n; }

이 주제에 대한 변형은 Microsoft C ++에만 해당됩니다.

__declspec(naked) bool __fastcall isOdd(const int x)
{
    __asm
    {
        mov eax,ecx
        mul eax
        mul eax
        mul eax
        mul eax
        mul eax
        mul eax
        ret
    }
}

2

비트 방식은 정수의 내부 표현에 따라 다릅니다. 모듈로는 모듈로 연산자가있는 곳이면 어디든 작동합니다. 예를 들어, 일부 시스템은 실제로 동적 언어와 같이 태깅에 저수준 비트를 사용하므로 원시 x & 1은 실제로 작동하지 않습니다.


2

IsOdd (int x) {return true; }

정확성 증명-모든 양의 정수 세트를 고려하고 홀수가 아닌 정수가 아닌 정수 세트가 있다고 가정하십시오. 양의 정수는 잘 정렬되어 있기 때문에 홀수가 아닌 가장 작은 수가 있으며, 그 자체로는 꽤 홀수이므로 숫자가 세트에있을 수 없습니다. 따라서이 세트는 비어 있지 않아야합니다. 홀수가 아닌 가장 큰 숫자를 찾는 것을 제외하고 음의 정수에 대해 반복하십시오.


2

가지고 다닐 수 있는:

i % 2 ? odd : even;

휴대 불가 :

i & 1 ? odd : even;

i << (BITS_PER_INT - 1) ? odd : even;

2

일부 사람들이 게시 한 것처럼이를 수행하는 방법에는 여러 가지가 있습니다. 에 따르면이 웹 사이트 가장 빠른 방법은 모듈러스 연산자입니다.

if (x % 2 == 0)
               total += 1; //even number
        else
               total -= 1; //odd number

그러나 여기에 몇 가지가 있습니다. 벤치 마크 된 다른 코드가 있습니다. 위의 일반적인 모듈러스 연산보다 느리게 실행 된 저자 .

if ((x & 1) == 0)
               total += 1; //even number
        else
               total -= 1; //odd number

System.Math.DivRem((long)x, (long)2, out outvalue);
        if ( outvalue == 0)
               total += 1; //even number
        else
               total -= 1; //odd number

if (((x / 2) * 2) == x)
               total += 1; //even number
        else
               total -= 1; //odd number

if (((x >> 1) << 1) == x)
               total += 1; //even number
        else
               total -= 1; //odd number

        while (index > 1)
               index -= 2;
        if (index == 0)
               total += 1; //even number
        else
               total -= 1; //odd number

tempstr = x.ToString();
        index = tempstr.Length - 1;
        //this assumes base 10
        if (tempstr[index] == '0' || tempstr[index] == '2' || tempstr[index] == '4' || tempstr[index] == '6' || tempstr[index] == '8')
               total += 1; //even number
        else
               total -= 1; //odd number

얼마나 많은 사람들이 Math.System.DivRem 방법을 알고 있었으며 왜 사용 합니까 ?



1

우리 연구 중에 부울 대수를 많이하지 않은 사람들을 위해 비트 연산자 방법에 대해 더 자세히 설명하기 위해 여기에 설명이 있습니다. 아마도 OP에는별로 유용하지 않지만 NUMBER & 1이 왜 작동하는지 명확하게 느끼고 싶었습니다.

위의 답변과 같이 음수가 표시되는 방식으로 인해이 방법이 작동하지 않을 수 있습니다. 실제로 각 언어가 음수 피연산자를 처리하는 방식이 다를 수 있으므로 모듈로 연산자 메소드를 손상시킬 수도 있습니다.

그러나 NUMBER가 항상 양수라는 것을 알고 있다면 잘 작동합니다.

위의 Tooony는 2 진 (및 치열)의 마지막 숫자 만 중요하다는 점을 지적했습니다.

부울 논리 AND 게이트는 1을 반환하려면 두 입력이 모두 1 (또는 고전압)이어야한다고 지시합니다.

1 & 0 = 0입니다.

0 & 1 = 0입니다.

0 & 0 = 0입니다.

1 & 1 = 1.

어떤 숫자를 이진수로 표현하면 (여기서는 8 비트 표현을 사용했습니다) 홀수는 끝에 1이 있고 짝수는 0이됩니다.

예를 들면 다음과 같습니다.

1 = 00000001

2 = 00000010

3 = 00000011

4 = 00000100

숫자를 가져 와서 비트 AND (java에서 &)를 1로 사용하면 00000001, = 1을 반환합니다. 또는 00000000 = 0은 숫자가 짝수임을 의미합니다.

예 :

홀수?

1 & 1 =

00000001 &

00000001 =

00000001 <— 홀수

2 & 1 =

00000010 및

00000001 =

00000000 <— 짝수

54 & 1 =

00000001 &

00110110 =

00000000 <— 짝수

이것이 이것이 작동하는 이유입니다.

if(number & 1){

   //Number is odd

} else {

   //Number is even
}

중복되어 죄송합니다.


1

수 제로 패리티 | 제로 http://tinyurl.com/oexhr3k

파이썬 코드 시퀀스.

# defining function for number parity check
def parity(number):
    """Parity check function"""
    # if number is 0 (zero) return 'Zero neither ODD nor EVEN',
    # otherwise number&1, checking last bit, if 0, then EVEN, 
    # if 1, then ODD.
    return (number == 0 and 'Zero neither ODD nor EVEN') \
            or (number&1 and 'ODD' or 'EVEN')

# cycle trough numbers from 0 to 13 
for number in range(0, 14):
    print "{0:>4} : {0:08b} : {1:}".format(number, parity(number))

산출:

   0 : 00000000 : Zero neither ODD nor EVEN
   1 : 00000001 : ODD
   2 : 00000010 : EVEN
   3 : 00000011 : ODD
   4 : 00000100 : EVEN
   5 : 00000101 : ODD
   6 : 00000110 : EVEN
   7 : 00000111 : ODD
   8 : 00001000 : EVEN
   9 : 00001001 : ODD
  10 : 00001010 : EVEN
  11 : 00001011 : ODD
  12 : 00001100 : EVEN
  13 : 00001101 : ODD

@ el.pescado, 감사합니다. 만약 0이 짝수라면, 얼마나 많은 쌍을 가지고 있습니까?

@ el.pescado, 네, 동의합니다. 그렇다면 조금 생각하면 왜 2로 나눕니 까? 우리가 둘로 나눌 때 알고 싶은 것은? 왜 3 등으로 나누지 않습니까?

@ el.pescado이 위키 백과 기사 Parity of Zero 가 잘못되었습니다. 이 기사에서 많은 사람들이 속였습니다. 윙크하기 전에 생각하십시오.

1
네가 옳아. 지금은 내가 :) 가장 포괄적 인 당신을 발견 다른 답변 읽었
el.pescado

@ el.pescado. 감사합니다. :) 이제 당신은 제로의 가장 친한 친구입니다. (hug)

1
I execute this code for ODD & EVEN:

#include <stdio.h>
int main()
{
    int number;
    printf("Enter an integer: ");
    scanf("%d", &number);

    if(number % 2 == 0)
        printf("%d is even.", number);
    else
        printf("%d is odd.", number);
}

0

토론을 위해 ...

주어진 숫자의 마지막 숫자 만 보면 짝수인지 홀수인지 확인할 수 있습니다. 부호, 부호 없음, 긍정적, 부정적-이것과 관련하여 모두 동일합니다. 그래서 이것은 모든 라운드에서 작동해야합니다 :-

void tellMeIfItIsAnOddNumberPlease(int iToTest){
  int iLastDigit;
  iLastDigit = iToTest - (iToTest / 10 * 10);
  if (iLastDigit % 2 == 0){
    printf("The number %d is even!\n", iToTest);
  } else {
    printf("The number %d is odd!\n", iToTest);
  }
}

여기서 핵심은 코드의 세 번째 줄에 있으며 나누기 연산자는 정수 나누기를 수행하므로 결과의 소수 부분이 누락됩니다. 예를 들어 222/10은 결과적으로 22를 제공합니다. 그런 다음 다시 10을 곱하면 220이됩니다. 원래 222에서 빼면 2로 끝납니다. 마법으로 원래 숫자의 마지막 숫자와 같은 숫자입니다. ;-) 괄호는 계산 순서를 상기시켜줍니다. 먼저 나누기와 곱셈을 수행 한 다음 원래 숫자에서 결과를 뺍니다. 뺄셈보다 나누기와 곱셈에 우선 순위가 높기 때문에 그것들을 생략 할 수 있지만, 이것은 "더 읽기 쉬운"코드를 제공합니다.

원한다면 모든 것을 완전히 읽을 수 없게 만들 수 있습니다. 최신 컴파일러에는 아무런 차이가 없습니다.

printf("%d%s\n",iToTest,0==(iToTest-iToTest/10*10)%2?" is even":" is odd");

그러나 향후 코드 유지 관리가 더 어려워 질 것입니다. 홀수에 대한 텍스트를 "짝수"로 변경한다고 상상해보십시오. 그런 다음 나중에 다른 사람이 변경 사항을 확인하고 svn diff 또는 이와 유사한 것을 수행하려고합니다 ...

이식성에 대해 걱정하지 않고 속도에 대해 더 걱정한다면 가장 중요한 부분을 살펴볼 수 있습니다. 해당 비트가 1로 설정되면 홀수이고, 0이면 짝수입니다. Intel의 x86 아키텍처와 같은 작은 엔디 언 시스템에서는 다음과 같습니다.-

if (iToTest & 1) {
  // Even
} else {
  // Odd
}

iToTest % 2 == 0으로가는 것이 정확히 무엇이 문제입니까? 마지막 숫자를 추출하는 부서를 낭비하고 있으므로 필요한 것보다 두 배 느립니다.
freespace

@freespace : 나는 그 이상을 낭비하지 않습니까? :-) 곱셈과 뺄셈도. 그러나 내가 감히 말하지 않은 두 솔루션 사이에서 가장 효율적인 것은 무엇입니까? 내 게시물의 첫 번째 줄을 다시 읽는다면 이것이 가장 빠른 해결책이라고 주장하지 마십시오.
Tooony

@ Tooony, 아, 내 유머 모자가 떨어졌습니다. 그것은 지금 다시 공식적으로 돌아왔다 : D 죄송합니다 :)
freespace

0

효율적으로하려면 비트 연산자 ( x & 1)를 사용하지만 읽을 수 있으려면 모듈로 2 ( x % 2)를 사용하십시오.


-1 : 효율적으로하려면 둘 중 하나를 사용하십시오. 이식성을 원하면을 사용하십시오 %. 읽을 수있게하려면을 사용하십시오 %. 흠, 여기에 패턴이 보입니다.
Thomas Eding

@trinithis, 패턴이 없으며이 솔루션은 당신보다 훨씬 낫습니다.
Subs

0

짝수 또는 홀수를 확인하는 것은 간단한 작업입니다.

정확히 2로 나눌 수있는 숫자는 홀수입니다.

우리는 단지 어떤 수의 나눗셈을 확인하고 나누기를 확인하기 위해 %연산자 를 사용합니다.

다른 경우를 사용하여 홀수 검사

if(num%2 ==0)  
{
    printf("Even");
}
else
{
    printf("Odd");
}

그렇지 않으면 짝수 또는 홀수를 확인하는 C 프로그램

조건부 / 테너 리 연산자 사용

(num%2 ==0) printf("Even") : printf("Odd");

조건부 연산자를 사용하여 짝수 또는 홀수를 확인하는 C 프로그램 .

비트 단위 연산자 사용

if(num & 1)  
{
    printf("Odd");
}
else 
{
    printf("Even");
}

삼항 연산자는 정확히 어디에 있습니까?
Beyondo

0

+ 66 % 더 빠름>!(i%2) / i%2 == 0

int isOdd(int n)
{
    return n & 1;
}

이진 에서 1 이면 정수의 마지막 비트를 검사합니다.

설명

Binary  :   Decimal
-------------------
0000    =   0
0001    =   1
0010    =   2
0011    =   3
0100    =   4
0101    =   5
0110    =   6
0111    =   7
1000    =   8
1001    =   9
and so on...

주의 가장 오른쪽 비트가 항상 1 홀수 번호.

우리의 오른쪽 비트 비트 AND 연산자 수표 반송 라인이 1이라면

그것을 참과 거짓으로 생각하십시오

우리가 n1 과 비교할 때 0001이진수 를 의미합니다 (0의 숫자는 중요하지 않습니다).
그럼 우리가 1 바이트 크기의 정수 n 을 가지고 있다고 상상해 봅시다 .

8 비트 / 8 이진수로 표현됩니다.

int n7 이고 1 과 비교하면 다음과 같습니다.

7 (1-byte int)|    0  0  0  0    0  1  1  1
       &
1 (1-byte int)|    0  0  0  0    0  0  0  1
********************************************
Result        |    F  F  F  F    F  F  F  T

어떤 F 는 거짓, T 는 참을 나타냅니다 .

그것은 비교 가 모두 사실 인 경우에만 가장 오른쪽 비트. 그래서, 자동적 7 & 1T의 후회.

가장 오른쪽에있는 비트를 확인하려면 어떻게합니까?

단순히 변경 n & 1n & 22 나타내는0010 이진수 등등.

비트 연산을 처음 접하는 경우 16 진수 표기법을 사용하는 것이 좋습니다
return n & 1;>> return n & 0x01;.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.