ฉันจะตรวจสอบว่าหมายเลขที่กำหนดเป็นเลขคู่หรือคี่ใน 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
ret
GCC 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 : ODD
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);
}
เพื่อการอภิปราย ...
คุณต้องดูตัวเลขสุดท้ายในจำนวนที่กำหนดเพื่อดูว่าเป็นเลขคู่หรือคี่ ลงนามไม่ได้ลงนามในเชิงบวกเป็นลบ - พวกเขาจะเหมือนกันทั้งหมดเกี่ยวกับเรื่องนี้ ดังนั้นนี่ควรจะใช้ได้ทุกรอบ: -
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 == 0
int 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;