Làm cách nào để kiểm tra xem một số đã cho là chẵn hay lẻ trong C?
Làm cách nào để kiểm tra xem một số đã cho là chẵn hay lẻ trong C?
Câu trả lời:
Sử dụng toán tử modulo (%) để kiểm tra xem có phần dư không khi chia cho 2:
if (x % 2) { /* x is odd */ }
Một số người đã chỉ trích câu trả lời của tôi ở trên nói rằng sử dụng x & 1 là "nhanh hơn" hoặc "hiệu quả hơn". Tôi không tin đây là trường hợp.
Vì tò mò, tôi đã tạo ra hai chương trình thử nghiệm tầm thường:
/* 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;
}
Sau đó tôi đã biên dịch những thứ này với gcc 4.1.3 trên một trong các máy của tôi 5 lần khác nhau:
Tôi đã kiểm tra đầu ra lắp ráp của mỗi trình biên dịch (sử dụng gcc -S) và thấy rằng trong mỗi trường hợp, đầu ra cho and.c và modulo.c giống hệt nhau (cả hai đều sử dụng lệnh andl $ 1,% eax). Tôi nghi ngờ đây là một tính năng "mới" và tôi nghi ngờ nó có từ phiên bản cổ. Tôi cũng nghi ngờ bất kỳ trình biên dịch không phức tạp hiện đại (được thực hiện trong 20 năm qua), thương mại hoặc nguồn mở, thiếu tối ưu hóa như vậy. Tôi sẽ thử nghiệm trên các trình biên dịch khác, nhưng hiện tại tôi không có sẵn bất kỳ trình biên dịch nào.
Nếu bất cứ ai khác quan tâm đến việc kiểm tra các trình biên dịch và / hoặc các mục tiêu nền tảng khác và nhận được một kết quả khác, tôi rất muốn biết.
Cuối cùng, phiên bản modulo được đảm bảo bởi tiêu chuẩn để hoạt động cho dù số nguyên là dương, âm hay bằng 0, bất kể việc biểu diễn các số nguyên đã ký. Phiên bản bitwise và phiên bản thì không. Vâng, tôi nhận ra bổ sung của hai là hơi phổ biến, vì vậy đây không thực sự là một vấn đề.
Các bạn đang waaaaaaaay quá hiệu quả. Những gì bạn thực sự muốn là:
public boolean isOdd(int num) {
int i = 0;
boolean odd = false;
while (i != num) {
odd = !odd;
i = i + 1;
}
return odd;
}
Lặp lại cho isEven
.
Tất nhiên, điều đó không làm việc cho các số âm. Nhưng với sự sáng chói đến sự hy sinh ...
Sử dụng số học bit:
if((x & 1) == 0)
printf("EVEN!\n");
else
printf("ODD!\n");
Điều này nhanh hơn so với sử dụng phép chia hoặc mô đun.
[Chế độ trò đùa = "bật"]
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;
}
}
[Chế độ trò đùa = "tắt"]
EDIT: Đã thêm các giá trị khó hiểu vào enum.
Đáp lại ffpf - tôi đã có chính xác lập luận tương tự với một đồng nghiệp nhiều năm trước, và câu trả lời là không , nó không hoạt động với các số âm.
Tiêu chuẩn C quy định rằng các số âm có thể được biểu diễn theo 3 cách:
Kiểm tra như thế này:
isEven = (x & 1);
sẽ hoạt động cho phần bù của 2 và biểu thị cường độ, nhưng không cho phần bù của 1.
Tuy nhiên, tôi tin rằng những điều sau đây sẽ hoạt động cho tất cả các trường hợp:
isEven = (x & 1) ^ ((-1 & 1) | ((x < 0) ? 0 : 1)));
Cảm ơn ffpf đã chỉ ra rằng hộp văn bản đã ăn mọi thứ sau khi tôi ít hơn nhân vật!
Một điều tốt đẹp là:
/*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
}
Lưu ý rằng phương pháp này sử dụng đệ quy đuôi liên quan đến hai chức năng. Nó có thể được thực hiện một cách hiệu quả (biến thành một vòng / cho đến khi loại vòng lặp) nếu trình biên dịch của bạn hỗ trợ đệ quy đuôi như trình biên dịch Scheme. Trong trường hợp này, ngăn xếp không nên tràn!
Một số chẵn nếu, khi chia cho hai, phần còn lại là 0. Một số là số lẻ nếu, khi chia cho 2, phần còn lại là 1.
// Java
public static boolean isOdd(int num){
return num % 2 != 0;
}
/* C */
int isOdd(int num){
return num % 2;
}
Phương pháp rất hay!
i % 2 == 0
Tôi muốn nói chỉ cần chia nó cho 2 và nếu có 0 phần còn lại, nó thậm chí, nếu không nó là số lẻ.
Sử dụng mô-đun (%) làm cho điều này dễ dàng.
ví dụ. 4% 2 = 0 do đó 4 thậm chí 5% 2 = 1 do đó 5 là số lẻ
Thêm một giải pháp cho vấn đề
(trẻ em được hoan nghênh bầu chọn)
bool isEven(unsigned int x)
{
unsigned int half1 = 0, half2 = 0;
while (x)
{
if (x) { half1++; x--; }
if (x) { half2++; x--; }
}
return half1 == half2;
}
Tôi sẽ xây dựng một bảng các số chẵn lẻ (0 nếu chẵn 1 nếu lẻ) của các số nguyên (để người ta có thể tra cứu: D), nhưng gcc sẽ không cho phép tôi tạo các mảng có kích thước như vậy:
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];
}
Vì vậy, thay vào đó hãy sử dụng định nghĩa toán học của chẵn và lẻ.
Một số nguyên n thậm chí nếu tồn tại một số nguyên k sao cho n = 2k.
Một số nguyên n là số lẻ nếu tồn tại một số nguyên k sao cho n = 2k + 1.
Đây là mã cho 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;
}
Đặt số nguyên C biểu thị các giá trị có thể có của int
trong một biên dịch C đã cho. (Lưu ý rằng số nguyên C là tập con của số nguyên.)
Bây giờ người ta có thể lo lắng rằng với một n đã cho trong các số nguyên C thì số nguyên k tương ứng có thể không tồn tại trong các số nguyên C. Nhưng với một ít bằng chứng, có thể chỉ ra rằng với mọi số nguyên n, | n | <= | 2n | (*), trong đó | n | là "n nếu n là dương và -n nếu không". Nói cách khác, với tất cả n trong số nguyên ít nhất một trong các lần giữ sau (chính xác là một trong hai trường hợp (1 và 2) hoặc trường hợp (3 và 4) trên thực tế nhưng tôi sẽ không chứng minh điều đó ở đây):
Trường hợp 1: n <= 2n.
Trường hợp 2: -n <= -2n.
Trường hợp 3: -n <= 2n.
Trường hợp 4: n <= -2n.
Bây giờ lấy 2k = n. (Như vậy không tồn tại nếu n chẵn, nhưng tôi sẽ không chứng minh điều đó ở đây. Nếu n thậm chí không phải là vòng lặp even
không thể quay lại sớm, vì vậy nó không thành vấn đề.) Nhưng điều này ngụ ý k <n nếu n không phải 0 bởi (*) và thực tế (một lần nữa không được chứng minh ở đây) rằng với mọi m, z trong các số nguyên 2m = z ngụ ý z không bằng m đã cho m không bằng 0. Trong trường hợp n là 0, 2 * 0 = 0 vì vậy 0 là chẵn, chúng ta đã hoàn thành (nếu n = 0 thì 0 nằm trong số nguyên C vì n nằm trong số nguyên C trong hàm even
, do đó k = 0 nằm trong số nguyên C). Do đó ak trong số nguyên C tồn tại cho n trong số nguyên C nếu n chẵn.
Một đối số tương tự cho thấy rằng nếu n là số lẻ, tồn tại ak trong các số nguyên C sao cho n = 2k + 1.
Do đó, các hàm even
và odd
được trình bày ở đây sẽ hoạt động đúng cho tất cả các số nguyên C.
i % 2
nhỏ hơn nhiều và có thể hiệu quả hơn.
%2
hoạt động cho tất cả các số nguyên.
// C#
bool isEven = ((i % 2) == 0);
typedef
hoặc #define
hoặc một cái gì đó.
Đây là một câu trả lời trong 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();
}
Thử cái này: return (((a>>1)<<1) == a)
Thí dụ:
a = 10101011
-----------------
a>>1 --> 01010101
a<<1 --> 10101010
b = 10011100
-----------------
b>>1 --> 01001110
b<<1 --> 10011100
Đọc cuộc thảo luận khá thú vị này, tôi nhớ rằng tôi có một chức năng nhạy cảm với thời gian trong thế giới thực, đã kiểm tra các số lẻ và chẵn trong vòng lặp chính. Đây là một hàm năng lượng nguyên, được đăng ở nơi khác trên StackOverflow, như sau. Các điểm chuẩn là khá ngạc nhiên. Ít nhất là trong chức năng trong thế giới thực này, modulo chậm hơn và đáng kể là như vậy. Người chiến thắng, với biên độ rộng, yêu cầu 67% thời gian của modul, là một cách tiếp cận hoặc (|) và không tìm thấy ở đâu trên trang này.
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;
}
Đối với 300 triệu vòng lặp, thời gian chuẩn như sau.
3.962 cái | và mặt nạ tiếp cận
4.851 và cách tiếp cận
5,850 cách tiếp cận%
Đối với những người nghĩ về lý thuyết, hoặc một danh sách ngôn ngữ lắp ráp, giải quyết các đối số như thế này, đây sẽ là một câu chuyện cảnh báo. Có nhiều điều trên thiên đường và trái đất, Horatio, hơn là mơ ước trong triết lý của bạn.
unsigned x
như x = x >> 1;
là hành vi được xác định thực hiện khi x < 0
. Không rõ tại sao x
và OrMask
khác nhau về loại. Đủ đơn giản để viết lại bằng cách sử dụng một while(x)
bài kiểm tra.
% 2
trường hợp bằng cách sử dụng bitwise &
. Tôi mới thử nghiệm điều này và kết quả hoàn toàn giống nhau (VS2015, Bản dựng phát hành với tất cả các tối ưu hóa, cả x86 và x64). Câu trả lời được chấp nhận cũng nêu điều này cho GCC (viết năm 2008).
or
sẽ nhanh hơn bất kỳ and
rất khó xảy ra, trên bất kỳ nền tảng / trình biên dịch nào. Ngay cả khi có một kết hợp nền tảng / trình biên dịch kỳ lạ như vậy (và bạn đã không đăng cả mã cũng không được sử dụng để thực hiện điểm chuẩn), tùy thuộc vào các trình biên dịch khác để hành xử tương tự sẽ là một đặt cược tối ưu hóa kém. Vì vậy, như tôi đã viết, tôi tự hỏi nền tảng / trình biên dịch này đã được thử nghiệm trên đó , bởi vì tôi gần như chắc chắn rằng nó không được đo chính xác.
Đây là phần tiếp theo cuộc thảo luận với @RocketRoy về câu trả lời của anh ấy , nhưng nó có thể hữu ích cho bất kỳ ai muốn so sánh các kết quả này.
tl; dr Từ những gì tôi đã thấy, cách tiếp cận của Roy ( (0xFFFFFFFF == (x | 0xFFFFFFFE)
) không hoàn toàn được tối ưu hóa x & 1
như mod
cách tiếp cận, nhưng trong thực tế, thời gian chạy sẽ trở nên bình đẳng trong mọi trường hợp.
Vì vậy, trước tiên tôi đã so sánh đầu ra được biên dịch bằng Compiler Explorer :
Chức năng được kiểm tra:
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 với -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 với -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
Ngả mũ xuống CLang, nó nhận ra rằng cả ba trường hợp đều có chức năng như nhau. Tuy nhiên, cách tiếp cận của Roy không được tối ưu hóa trong GCC, vì vậy YMMV.
Nó tương tự với Visual Studio; kiểm tra bản phát hành tháo gỡ x64 (VS2015) cho ba chức năng này, tôi có thể thấy rằng phần so sánh bằng với các trường hợp "mod" và "và", và lớn hơn một chút cho trường hợp "hoặc" của 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)
Tuy nhiên, sau khi chạy một điểm chuẩn thực tế để so sánh ba tùy chọn này (mod đơn giản, bitwise hoặc, bitwise và), kết quả hoàn toàn bằng nhau (một lần nữa, Visual Studio 2005 x86 / x64, Bản dựng phát hành, không có trình gỡ lỗi đính kèm).
Tập hợp phát hành sử dụng test
hướng dẫn cho and
và mod
các trường hợp, trong khi trường hợp của Roy sử dụng cmp eax,0FFFFFFFFh
cách tiếp cận, nhưng nó không được kiểm soát và tối ưu hóa nhiều nên không có sự khác biệt trong thực tế.
Kết quả của tôi sau 20 lần chạy (i7 3610QM, gói điện năng Windows 10 được đặt thành Hiệu suất cao):
[Kiểm tra: Plain mod 2] THỜI GIAN AVERAGE: 689,29 ms (Tương đối khác: + 0,000%) [Kiểm tra: Bitwise hoặc] THỜI GIAN AVERAGE: 689,63 ms (Tương đối khác: + 0,048%) [Kiểm tra: Bitwise và] THỜI GIAN AVERAGE: 687,80 ms (Khác biệt tương đối: -0,217%)
Sự khác biệt giữa các tùy chọn này nhỏ hơn 0,3%, do đó, rõ ràng việc lắp ráp là bằng nhau trong mọi trường hợp.
Đây là mã nếu bất cứ ai muốn thử, với một cảnh báo mà tôi chỉ kiểm tra nó trên Windows (kiểm tra #if LINUX
điều kiện cho get_time
định nghĩa và thực hiện nó nếu cần, lấy từ câu trả lời này ).
#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;
}
Tôi biết đây chỉ là đường cú pháp và chỉ áp dụng trong .net nhưng còn phương pháp mở rộng thì sao ...
public static class RudiGroblerExtensions
{
public static bool IsOdd(this int i)
{
return ((i % 2) != 0);
}
}
Bây giờ bạn có thể làm như sau
int i = 5;
if (i.IsOdd())
{
// Do something...
}
Trong "danh mục sáng tạo nhưng khó hiểu" tôi cung cấp:
int isOdd(int n) { return n ^ n * n ? isOdd(n * n) : n; }
Một biến thể về chủ đề này dành riêng cho 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
}
}
Phương pháp bitwise phụ thuộc vào biểu diễn bên trong của số nguyên. Modulo sẽ làm việc ở bất cứ nơi nào có toán tử modulo. Ví dụ: một số hệ thống thực sự sử dụng các bit cấp thấp để gắn thẻ (như ngôn ngữ động), do đó, x & 1 thô sẽ không thực sự hoạt động trong trường hợp đó.
IsOdd (int x) {return true; }
Bằng chứng về tính chính xác - xem xét tập hợp của tất cả các số nguyên dương và giả sử có một bộ số nguyên không trống không phải là số lẻ. Bởi vì các số nguyên dương được sắp xếp hợp lý, sẽ có một số nhỏ nhất không phải là số lẻ, mà bản thân nó khá kỳ lạ, nên rõ ràng số đó không thể có trong tập hợp. Do đó, bộ này không thể trống. Lặp lại cho các số nguyên âm ngoại trừ tìm số lớn nhất không lẻ.
Như một số người đã đăng, có rất nhiều cách để làm điều này. Theo trang web này , cách nhanh nhất là toán tử mô đun:
if (x % 2 == 0)
total += 1; //even number
else
total -= 1; //odd number
Tuy nhiên, đây là một số mã khác được đánh dấu bởi tác giả chạy chậm hơn so với hoạt động mô đun phổ biến ở trên:
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
Có bao nhiêu người thậm chí biết đến phương pháp Math.System.DivRem hoặc tại sao họ sẽ sử dụng nó ??
Để giải thích chi tiết hơn về phương pháp toán tử bitwise cho những người trong chúng ta đã không làm đại số boolean nhiều trong các nghiên cứu của chúng tôi, đây là một lời giải thích. Có lẽ không được sử dụng nhiều cho OP, nhưng tôi cảm thấy muốn làm rõ lý do tại sao SỐ & 1 hoạt động.
Xin lưu ý như ai đó đã trả lời ở trên, cách các số âm được thể hiện có thể dừng phương pháp này hoạt động. Trong thực tế, nó thậm chí có thể phá vỡ phương thức toán tử modulo vì mỗi ngôn ngữ có thể khác nhau về cách nó xử lý các toán hạng âm.
Tuy nhiên nếu bạn biết rằng SỐ sẽ luôn tích cực, thì điều này hoạt động tốt.
Như Tooony ở trên đã chỉ ra rằng chỉ có chữ số cuối cùng trong nhị phân (và từ chối) là quan trọng.
Một cổng logic Boolean ra lệnh rằng cả hai đầu vào phải là 1 (hoặc điện áp cao) cho 1 được trả về.
1 & 0 = 0.
0 & 1 = 0.
0 & 0 = 0.
1 & 1 = 1.
Nếu bạn biểu thị bất kỳ số nào dưới dạng nhị phân (tôi đã sử dụng biểu diễn 8 bit ở đây), số lẻ có 1 ở cuối, số chẵn có 0.
Ví dụ:
1 = 00000001
2 = 00000010
3 = 00000011
4 = 00000100
Nếu bạn lấy bất kỳ số nào và sử dụng bitwise AND (& trong java) thì nó sẽ trả về 00000001, = 1 có nghĩa là số đó là số lẻ. Hoặc 00000000 = 0, có nghĩa là số chẵn.
Ví dụ
Là số lẻ?
1 & 1 =
00000001 &
00000001 =
00000001 <- lẻ
2 & 1 =
00000010 &
00000001 =
00000000 <- Chẵn
54 & 1 =
00000001 &
00110110 =
00000000 <- Chẵn
Đây là lý do tại sao điều này hoạt động:
if(number & 1){
//Number is odd
} else {
//Number is even
}
Xin lỗi nếu điều này là dư thừa.
Số không chẵn lẻ | không http://tinyurl.com/oexhr3k
Trình tự mã Python.
# 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))
Đầu ra:
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);
}
Vì lợi ích của cuộc thảo luận ...
Bạn chỉ cần nhìn vào chữ số cuối cùng trong bất kỳ số đã cho nào để xem nó là số chẵn hay lẻ. Đã ký, không dấu, tích cực, tiêu cực - tất cả đều giống nhau về vấn đề này. Vì vậy, điều này sẽ làm việc tất cả các vòng: -
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);
}
}
Khóa ở đây nằm trong dòng mã thứ ba, toán tử chia thực hiện phép chia số nguyên, do đó kết quả bị thiếu phần phân số của kết quả. Vì vậy, ví dụ 222/10 sẽ cho 22 kết quả. Sau đó nhân nó lại với 10 và bạn có 220. Trừ đi số đó từ 222 gốc và bạn kết thúc bằng 2, bằng phép thuật là số giống với chữ số cuối cùng trong số ban đầu. ;-) Dấu ngoặc đơn ở đó để nhắc nhở chúng ta về thứ tự tính toán được thực hiện. Đầu tiên thực hiện phép chia và phép nhân, sau đó trừ kết quả khỏi số ban đầu. Chúng ta có thể loại bỏ chúng, vì mức độ ưu tiên cao hơn cho phép chia và phép nhân so với phép trừ, nhưng điều này mang lại cho chúng ta mã "dễ đọc hơn".
Chúng tôi có thể làm cho tất cả hoàn toàn không thể đọc được nếu chúng tôi muốn. Nó sẽ không tạo ra sự khác biệt nào cho trình biên dịch hiện đại: -
printf("%d%s\n",iToTest,0==(iToTest-iToTest/10*10)%2?" is even":" is odd");
Nhưng nó sẽ làm cho cách mã khó hơn để duy trì trong tương lai. Chỉ cần tưởng tượng rằng bạn muốn thay đổi văn bản cho các số lẻ thành "không chẵn". Sau đó, một người khác sau đó muốn tìm hiểu những thay đổi bạn đã thực hiện và thực hiện một svn diff hoặc tương tự ...
Nếu bạn không lo lắng về tính di động nhưng nhiều hơn về tốc độ, bạn có thể xem xét một chút ít quan trọng nhất. Nếu bit đó được đặt thành 1 thì đó là số lẻ, nếu là 0 thì đó là số chẵn. Trên một hệ thống endian nhỏ, như kiến trúc x86 của Intel, nó sẽ giống như thế này: -
if (iToTest & 1) {
// Even
} else {
// Odd
}
Nếu bạn muốn hiệu quả, hãy sử dụng toán tử bit ( x & 1
), nhưng nếu bạn muốn có thể đọc được, hãy sử dụng modulo 2 ( x % 2
)
%
. Nếu bạn muốn nó có thể đọc được, hãy sử dụng %
. Hmmm, tôi thấy một mô hình ở đây.
Kiểm tra chẵn hoặc lẻ là một nhiệm vụ đơn giản.
Chúng ta biết rằng bất kỳ số nào chia hết cho 2 đều là số lẻ khác.
Chúng tôi chỉ cần kiểm tra tính chia hết của bất kỳ số nào và để kiểm tra tính chia hết, chúng tôi sử dụng %
toán tử
Kiểm tra chẵn sử dụng lẻ nếu khác
if(num%2 ==0)
{
printf("Even");
}
else
{
printf("Odd");
}
Chương trình C để kiểm tra chẵn hoặc lẻ bằng cách sử dụng nếu khác
Sử dụng toán tử có điều kiện / Ternary
(num%2 ==0) printf("Even") : printf("Odd");
Chương trình C để kiểm tra chẵn hoặc lẻ bằng toán tử có điều kiện .
Sử dụng toán tử Bitwise
if(num & 1)
{
printf("Odd");
}
else
{
printf("Even");
}
!(i%2) / i%2 == 0
int isOdd(int n)
{
return n & 1;
}
Mã kiểm tra bit cuối của số nguyên nếu là 1 trong Nhị phân
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...
Lưu ý bit ngoài cùng bên phải luôn là 1 cho các số lẻ .
các & Bitwise AND hành kiểm tra các bit ngoài cùng bên phải trong chúng tôi trở lại dòng nếu nó 1
Khi chúng ta so sánh n với 1 có nghĩa là 0001
nhị phân (số không không quan trọng).
sau đó hãy tưởng tượng rằng chúng ta có số nguyên n với kích thước 1 byte.
Nó được biểu thị bằng các chữ số 8 bit / 8 nhị phân.
Nếu int n là 7 và chúng ta so sánh nó với 1 , thì giống như
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
Mà F là viết tắt của false và T là true.
Nó chỉ so sánh bit ngoài cùng bên phải nếu cả hai đều đúng. Vì vậy, tự động
7 & 1
là T rue.
Đơn giản chỉ cần thay đổi n & 1
thành n & 2
2 đại diện 0010
trong Nhị phân, v.v.
Tôi đề nghị sử dụng ký hiệu thập lục phân nếu bạn là người mới bắt đầu hoạt động bitwise
return n & 1;
>> return n & 0x01;
.