ฉันจะตรวจสอบว่าหมายเลขที่กำหนดเป็นเลขคู่หรือคี่ใน C ได้อย่างไร
ฉันจะตรวจสอบว่าหมายเลขที่กำหนดเป็นเลขคู่หรือคี่ใน C ได้อย่างไร
คำตอบ:
ใช้โอเปอเรเตอร์แบบโมดูโล (%) เพื่อตรวจสอบว่ามีเศษที่เหลืออยู่เมื่อหารด้วย 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;
}ฉันรวบรวมเหล่านี้ด้วย gcc 4.1.3 ในหนึ่งในเครื่องของฉัน 5 ครั้งที่แตกต่างกัน:
ฉันตรวจสอบเอาต์พุตแอสเซมบลีของแต่ละคอมไพล์ (โดยใช้ gcc -S) และพบว่าในแต่ละกรณีเอาต์พุตสำหรับ and.c และ modulo.c เหมือนกัน (ทั้งคู่ใช้คำสั่ง andl $ 1,% eax) ฉันสงสัยว่านี่เป็นฟีเจอร์ "ใหม่" และฉันสงสัยว่ามันจะย้อนไปถึงเวอร์ชั่นเก่า ฉันยังสงสัยในปัจจุบันคอมไพเลอร์ (ทำใน 20 ปีที่ผ่านมา) ใด ๆ ที่ไม่ใช่ arcane คอมไพเลอร์เชิงพาณิชย์หรือโอเพนซอร์สขาดการเพิ่มประสิทธิภาพดังกล่าว ฉันจะทดสอบคอมไพเลอร์อื่น ๆ แต่ฉันไม่สามารถใช้ได้ในขณะนี้
หากใครก็ตามที่สนใจที่จะทดสอบคอมไพเลอร์และ / หรือเป้าหมายแพลตฟอร์มอื่น ๆ และได้รับผลที่แตกต่างกันฉันก็สนใจที่จะรู้
ในที่สุดรุ่นโมดูโล่รับประกันโดยมาตรฐานในการทำงานไม่ว่าจะเป็นจำนวนเต็มบวกลบหรือศูนย์โดยไม่คำนึงถึงการใช้งานของการแสดงจำนวนเต็มลงนาม บิต - และเวอร์ชันไม่ใช่ ใช่ฉันรู้ว่าส่วนประกอบสองอย่างนั้นค่อนข้างแพร่หลายดังนั้นนี่จึงไม่ใช่ปัญหา
พวกคุณมีประสิทธิภาพมากเกินไป สิ่งที่คุณต้องการคือ:
public boolean isOdd(int num) {
  int i = 0;
  boolean odd = false;
  while (i != num) {
    odd = !odd;
    i = i + 1;
  }
  return odd;
}isEvenทำซ้ำสำหรับ
แน่นอนว่าไม่ได้ผลกับจำนวนลบ แต่ด้วยความฉลาดมาเสียสละ ...
ใช้เลขคณิตบิต:
if((x & 1) == 0)
    printf("EVEN!\n");
else
    printf("ODD!\n");สิ่งนี้เร็วกว่าการใช้การหารหรือโมดูลัส
[โหมดโจ๊ก = "เปิด"]
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;
  }
}[โหมดโจ๊ก = "ปิด"]
แก้ไข: เพิ่มค่าความสับสนให้กับ enum
เพื่อตอบสนองต่อffpf - ฉันมีข้อโต้แย้งเดียวกันกับเพื่อนร่วมงานเมื่อหลายปีก่อนและคำตอบคือไม่มันไม่ทำงานกับจำนวนลบ
มาตรฐาน C กำหนดให้ตัวเลขลบสามารถแสดงได้ 3 วิธี:
การตรวจสอบเช่นนี้:
isEven = (x & 1);จะใช้งานได้สำหรับส่วนเติมเต็มและ 2 ของเครื่องหมายและขนาด แต่ไม่ใช่สำหรับส่วนเสริม 1
อย่างไรก็ตามฉันเชื่อว่าสิ่งต่อไปนี้ใช้ได้กับทุกกรณี:
isEven = (x & 1) ^ ((-1 & 1) | ((x < 0) ? 0 : 1)));ขอบคุณ ffpf ที่ชี้ให้เห็นว่ากล่องข้อความกำลังกินทุกอย่างหลังจากตัวละครของฉันน้อยกว่า!
สิ่งที่ดีคือ:
/*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 ในกรณีนี้สแต็คไม่ควรล้น!
ตัวเลขจะเท่ากับแม้ว่าเมื่อหารด้วยสองส่วนที่เหลือจะเป็น 0 ตัวเลขนั้นจะเป็นเลขคู่ถ้าหากหารด้วย 2 ส่วนที่เหลือจะเท่ากับ 1
// Java
public static boolean isOdd(int num){
    return num % 2 != 0;
}
/* C */
int isOdd(int num){
    return num % 2;
}วิธีการที่ยอดเยี่ยม!
i % 2 == 0ผมจะบอกว่าหารด้วย 2 และถ้ามี 0 เหลือ, มันจะเป็นอย่างนั้น, มิฉะนั้นมันจะแปลก
การใช้มอดุลัส (%) ทำให้เป็นเรื่องง่าย
เช่น. 4% 2 = 0 ดังนั้น 4 จึงเป็น 5% 2 = 1 ดังนั้น 5 จึงเป็นเลขคี่
อีกหนึ่งวิธีแก้ปัญหา
(เด็กสามารถลงคะแนนได้)
bool isEven(unsigned int x)
{
  unsigned int half1 = 0, half2 = 0;
  while (x)
  {
     if (x) { half1++; x--; }
     if (x) { half2++; x--; }
  }
  return half1 == half2;
}ฉันจะสร้างตารางของ parities (0 ถ้าแม้ 1 ถ้าคี่) ของจำนวนเต็ม (ดังนั้นหนึ่งสามารถทำการค้นหา: 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 เป็นเลขคี่ถ้ามีจำนวนเต็ม k อยู่โดยที่ n = 2k + 1
นี่คือรหัสสำหรับมัน:
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 เป็นชุดย่อยของจำนวนเต็ม)
ทีนี้เราอาจกังวลว่าสำหรับ n ที่กำหนดใน C-integers ที่จำนวนเต็ม 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 (เช่น Ak มีอยู่ถ้า n ยังอยู่ แต่ฉันจะไม่พิสูจน์ที่นี่ถ้า n ไม่ได้แล้ววนevenกลับล้มเหลวในการกลับก่อนแต่ทว่ามันไม่สำคัญ) แต่นี่ก็หมายถึง k <n ถ้า n ไม่ใช่ 0 โดย (*) และความจริง (ไม่ได้พิสูจน์ที่นี่อีก) ว่าสำหรับ m ทั้งหมด, z ในจำนวนเต็ม 2m = z หมายถึง z ไม่เท่ากับ m ที่ให้ m คือ 0 ไม่ใช่ในกรณีที่ n คือ 0, 2 * 0 = 0 ดังนั้น 0 ถึงแม้ว่าเราจะเสร็จแล้ว (ถ้า n = 0 แล้ว 0 อยู่ใน C-integers เพราะ n อยู่ใน C-integer ในฟังก์ชันevenดังนั้น k = 0 จึงอยู่ใน C-integers) ดังนั้น ak ในจำนวนเต็ม C มีอยู่สำหรับ n ใน C-integers หาก n เป็นเลขคู่
อาร์กิวเมนต์ที่คล้ายกันแสดงว่าถ้า n เป็นเลขคี่มีค่า ak ในจำนวนเต็ม C เช่นนั้น n = 2k + 1
ดังนั้นฟังก์ชั่นevenและoddการนำเสนอที่นี่จะทำงานได้อย่างถูกต้องสำหรับ C-integers ทั้งหมด
i % 2มีขนาดเล็กมากและอาจมีประสิทธิภาพมากกว่า
                    %2ใช้ได้กับจำนวนเต็มทั้งหมด
                    // C#
bool isEven = ((i % 2) == 0);typedefหรือ#defineหรือบางสิ่งบางอย่าง
                    นี่คือคำตอบใน 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();
}ลองสิ่งนี้: return (((a>>1)<<1) == a)
ตัวอย่าง:
a     =  10101011
-----------------
a>>1 --> 01010101
a<<1 --> 10101010
b     =  10011100
-----------------
b>>1 --> 01001110
b<<1 --> 10011100การอ่านการสนทนานี้ค่อนข้างสนุกสนานฉันจำได้ว่าฉันมีฟังก์ชั่นตามเวลาจริงในโลกแห่งความเป็นจริงและทดสอบตัวเลขคี่และคู่ภายในวงหลัก มันเป็นฟังก์ชั่นพลังงานจำนวนเต็มโพสต์ที่อื่นใน 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;
}สำหรับ 300 ล้านลูปการกำหนดเวลามาตรฐานมีดังนี้
3.962 และวิธีการหน้ากาก
4.851 & วิธีการ
5.850 วิธีการ%
สำหรับคนที่คิดว่าทฤษฎีหรือรายการภาษาแอสเซมบลีตั้งหลักแหล่งข้อโต้แย้งเช่นนี้ควรเป็นเรื่องเตือน มีสิ่งต่าง ๆ ในสวรรค์และโลก Horatio มากกว่าที่คุณฝันไว้ในปรัชญาของคุณ
unsigned xเป็นคือการดำเนินการกำหนดพฤติกรรมเมื่อx = x >> 1; x < 0ไม่ชัดเจนว่าทำไมxและOrMaskแตกต่างกันในประเภท ง่ายพอที่จะเขียนใหม่โดยใช้การwhile(x)ทดสอบ
                    % 2 &ฉันเพิ่งทดสอบสิ่งนี้และผลลัพธ์จะเหมือนกันอย่างสมบูรณ์ (VS2015, Release builds พร้อมการปรับแต่งทั้งหมดทั้ง x86 และ x64) คำตอบที่ได้รับการยอมรับยังระบุสิ่งนี้สำหรับ GCC (เขียนในปี 2008)
                    orจะเร็วกว่าที่andไม่น่าเป็นไปได้สูงในแพลตฟอร์ม / คอมไพเลอร์ แม้ว่าจะมีแพลตฟอร์มที่แปลกประหลาด / คอมโบคอมไพเลอร์ (และคุณยังไม่ได้โพสต์ไม่ว่าจะเป็นหรือรหัสที่ใช้ในการทำเกณฑ์มาตรฐาน) ทั้งนี้ขึ้นอยู่กับคอมไพเลอร์อื่น ๆ ที่ทำตัวเหมือนกัน ดังนั้นอย่างที่ฉันเขียนฉันสงสัยว่าแพล็ตฟอร์ม / คอมไพเลอร์นี้ผ่านการทดสอบเพราะฉันเกือบแน่ใจว่ามันไม่ได้วัดอย่างถูกต้อง
                    นี่คือการติดตามการสนทนากับ @RocketRoy เกี่ยวกับคำตอบของเขาแต่อาจเป็นประโยชน์กับทุกคนที่ต้องการเปรียบเทียบผลลัพธ์เหล่านี้
tl; drจากสิ่งที่ฉันได้เห็นแนวทางของ Roy ( (0xFFFFFFFF == (x | 0xFFFFFFFE)) ไม่ได้รับการปรับอย่างสมบูรณ์ให้x & 1เป็นmodแนวทาง แต่ในทางปฏิบัติเวลาที่ใช้ควรจะเปิดออกเท่ากันในทุกกรณี
ดังนั้นก่อนอื่นฉันเปรียบเทียบผลลัพธ์ที่คอมไพล์ด้วยCompiler Explorer :
ฟังก์ชั่นการทดสอบ:
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));
}   CLANG 3.9.0 ด้วย -O3:
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
        retGCC 6.2 ด้วย -O3:
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; การตรวจสอบ disassembly Release x64 (VS2015) สำหรับฟังก์ชั่นทั้งสามนี้ฉันจะเห็นว่าส่วนการเปรียบเทียบมีค่าเท่ากันสำหรับ "mod" และ "และ" และ "case" และใหญ่กว่าเล็กน้อยสำหรับ Roy: หรือ
// 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)อย่างไรก็ตามหลังจากรันเกณฑ์มาตรฐานที่แท้จริงสำหรับการเปรียบเทียบสามตัวเลือกเหล่านี้ (mod ธรรมดา, bitwise หรือ, Bitwise และ) ผลลัพธ์ที่ได้นั้นมีค่าเท่ากันอย่างสมบูรณ์ (อีกครั้ง Visual Studio 2005 x86 / x64, Build build, ไม่มี debugger
ชุดประกอบที่ใช้testคำสั่งandและmodเคสในขณะที่เคสของ Roy ใช้cmp eax,0FFFFFFFFhวิธีการนี้ แต่มันไม่ได้รับการควบคุมและปรับให้เหมาะสมดังนั้นจึงไม่มีความแตกต่างในทางปฏิบัติ
ผลลัพธ์ของฉันหลังจากการรัน 20 ครั้ง (i7 3610QM, แผนการใช้พลังงานของ Windows 10 กำหนดเป็นประสิทธิภาพสูง):
[ทดสอบ: mod ธรรมดา 2] เวลาเฉลี่ย: 689.29 ms (ความแตกต่างสัมพัทธ์: + 0.000%) [ทดสอบ: บิตหรือ] เวลาโดยเฉลี่ย: 689.63 ms (สัมพัทธ์ต่าง: + 0.048%) [ทดสอบ: บิตและ] เวลาโดยเฉลี่ย: 687.80 มิลลิวินาที (ความต่างสัมพัทธ์: -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;
}ฉันรู้ว่านี่เป็นเพียงวากยสัมพันธ์น้ำตาลและใช้ได้เฉพาะใน. netแต่สิ่งที่เกี่ยวกับวิธีการขยาย ...
public static class RudiGroblerExtensions
{
    public static bool IsOdd(this int i)
    {
        return ((i % 2) != 0);
    }
}ตอนนี้คุณสามารถทำดังต่อไปนี้
int i = 5;
if (i.IsOdd())
{
    // Do something...
}ในหมวดหมู่ "สร้างสรรค์ แต่สับสน" ฉันขอเสนอ:
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
    }
}วิธีการ bitwise ขึ้นอยู่กับการแสดงภายในของจำนวนเต็ม โมดูโล่จะทำงานได้ทุกที่ที่มีโอเปอเรเตอร์แบบโมดูโล่ ตัวอย่างเช่นบางระบบใช้บิตระดับต่ำจริง ๆ สำหรับการแท็ก (เช่นภาษาไดนามิก) ดังนั้น raw x & 1 จะไม่ทำงานในกรณีนั้น
IsOdd (int x) {return true; }
หลักฐานความถูกต้อง - พิจารณาชุดของจำนวนเต็มบวกทั้งหมดและสมมติว่ามีชุดจำนวนเต็มที่ไม่ว่างที่ไม่ใช่เลขคี่ เนื่องจากเลขจำนวนเต็มบวกนั้นได้รับคำสั่งอย่างดีจะมีจำนวนน้อยที่สุดไม่ใช่คี่ซึ่งในตัวมันเองค่อนข้างแปลกดังนั้นชัดเจนว่าตัวเลขไม่สามารถอยู่ในชุดได้ ดังนั้นชุดนี้จะต้องไม่ว่างเปล่า ทำซ้ำสำหรับจำนวนเต็มลบยกเว้นมองหาจำนวนที่ไม่ผิด
พกพา:
i % 2 ? odd : even;unportable:
i & 1 ? odd : even;
i << (BITS_PER_INT - 1) ? odd : even;ในขณะที่บางคนโพสต์มีหลายวิธีในการทำเช่นนี้ ตามเว็บไซต์นี้วิธีที่เร็วที่สุดคือตัวดำเนินการโมดูลัส
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หรือทำไมพวกเขาถึงใช้มัน
เพื่อให้รายละเอียดเพิ่มเติมเกี่ยวกับวิธีการตัวดำเนินการระดับบิตสำหรับพวกเราที่ไม่ได้ทำพีชคณิตแบบบูลมากในระหว่างการศึกษาของเรานี่คือคำอธิบาย อาจไม่ได้ใช้ประโยชน์อย่างมากกับ OP แต่ฉันรู้สึกอยากทำให้มันชัดเจนว่าทำไม NUMBER & 1 ถึงทำงาน
โปรดทราบเช่นเดียวกับใครบางคนตอบข้างต้นวิธีการแสดงจำนวนลบสามารถหยุดวิธีนี้ได้ ในความเป็นจริงมันยังสามารถแบ่งวิธีโอเปอเรเตอร์ของโมดูโล่ด้วยเช่นกันเนื่องจากแต่ละภาษาสามารถแตกต่างกันในวิธีที่มันเกี่ยวข้องกับตัวถูกดำเนินการเชิงลบ
อย่างไรก็ตามถ้าคุณรู้ว่า NUMBER จะเป็นค่าบวกเสมอ
เนื่องจาก Tooony ด้านบนได้ระบุว่าเฉพาะเลขตัวสุดท้ายในระบบไบนารี่
ตรรกะบูลีนและเกทกำหนดว่าอินพุตทั้งสองต้องเป็น 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
หากคุณใช้ตัวเลขใด ๆ และใช้ bitwise 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
}ขออภัยถ้านี่ซ้ำซ้อน
Number Zero parity | ศูนย์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 : ODDI 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);
}เพื่อการอภิปราย ...
คุณต้องดูตัวเลขสุดท้ายในจำนวนที่กำหนดเพื่อดูว่าเป็นเลขคู่หรือคี่ ลงนามไม่ได้ลงนามในเชิงบวกเป็นลบ - พวกเขาจะเหมือนกันทั้งหมดเกี่ยวกับเรื่องนี้ ดังนั้นนี่ควรจะใช้ได้ทุกรอบ: -
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 มันจะเป็นเลขคู่ ในระบบ endian เล็ก ๆ น้อย ๆ เช่นสถาปัตยกรรม x86 ของ Intel มันจะเป็นแบบนี้: -
if (iToTest & 1) {
  // Even
} else {
  // Odd
}ถ้าคุณต้องการที่จะมีประสิทธิภาพใช้ตัวดำเนินการระดับบิต ( x & 1) แต่ถ้าคุณต้องการให้สามารถอ่านได้ใช้ modulo 2 ( x % 2)
%ถ้าคุณอยากให้มันเป็นแบบพกพาใช้งาน %หากคุณต้องการที่จะอ่านได้ใช้ อืมฉันเห็นรูปแบบที่นี่
                    การตรวจสอบคู่หรือคี่เป็นงานง่าย
เรารู้ว่าจำนวนใด ๆ ที่หารด้วย 2 ได้อย่างเลขคู่นั้นก็เลขคี่
เราเพียงแค่ต้องตรวจสอบความหารของจำนวนใด ๆ และสำหรับการตรวจสอบความหารที่เราใช้ %ประกอบการ
ตรวจสอบการใช้งานที่แปลกแม้กระทั่งถ้าอื่น
if(num%2 ==0)  
{
    printf("Even");
}
else
{
    printf("Odd");
}โปรแกรม C เพื่อตรวจสอบว่าคู่หรือคี่ใช้ถ้าอื่น
การใช้ตัวดำเนินการตามเงื่อนไข / ที่สาม
(num%2 ==0) printf("Even") : printf("Odd");โปรแกรม C เพื่อตรวจสอบคี่ได้หรือใช้ประกอบการที่มีเงื่อนไข
ใช้ตัวดำเนินการ Bitwise
if(num & 1)  
{
    printf("Odd");
}
else 
{
    printf("Even");
}!(i%2) / i%2 == 0int isOdd(int n)
{
    return n & 1;
}รหัสจะตรวจสอบบิตสุดท้ายของจำนวนเต็มถ้าเป็น1ใน Binary
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 เสมอสำหรับหมายเลขคี่
ตัวดำเนินการ& bitwise AND ตรวจสอบบิตขวาสุดในบรรทัดส่งคืนของเราหากเป็น 1
เมื่อเราเปรียบเทียบnกับ 1ซึ่งหมายถึงเป็น0001เลขฐานสอง (จำนวนศูนย์ไม่สำคัญ) 
ลองสมมุติว่าเรามีจำนวนเต็มnด้วยขนาด 1 ไบต์
มันจะถูกแทนด้วยตัวเลข 8-bit / 8-binary
ถ้า int nคือ7และเราเปรียบเทียบกับ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หมายถึง false และTสำหรับ true
มันเปรียบเทียบเพียงบิตที่ถูกต้องที่สุดหากพวกเขาเป็นทั้งจริง ดังนั้นโดยอัตโนมัติ
7 & 1คือT rue
เพียงแค่เปลี่ยน n & 1ไปn & 2ซึ่งแสดงให้เห็นถึง 2 0010ในไบนารีและอื่น ๆ
ผมขอแนะนำให้ใช้เลขฐานสิบหกถ้าคุณจะเริ่มต้นในการดำเนินงาน Bitwise >>
return n & 1;return n & 0x01;