题
我怎么可以检查,如果给定人数为偶数或奇数在C?
解决方案
使用模(%)操作者检查,如果有一个剩余时除以2:
if (x % 2) { /* x is odd */ }
一些人批评我以上的答案,说明使用x1"快"或"更高效率地"。我不相信这是这种情况。
出于好奇,我创建了两个平凡试验的情况下方案:
/* 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;
}
我然后汇编这些与海湾合作委员会4.1.3在我的机器有5个不同的时间:
- 有没有优化的标志。
- -O
- 与操作系统
- 与-O2
- 与O3
我检查了大会的每一个输出的汇编(使用海湾合作委员会-S),并发现,在每一种情况下,出于和。c模。c相同(它们都使用的电平$1,%eax指令)。我怀疑这是一个"新的"功能,而我怀疑它的历史可以追溯到古代的版本。我也怀疑的任何现代化(制在过去20年)非神秘的编译器、商业或开放源,缺乏这样的优化。我将试验在其他编译器,但我没有任何可用的时刻。
如果任何人愿意测试的其他汇编者和/或平台的目标,并取得不同的结果,我会很感兴趣知道。
最后,该模版本是 保证 通过的标准工作是否整数是积极的、消极的或零,不论的执行情况的代表签署的整数。按位和版本不是。是的,我意识到两个补是有点普遍存在,所以这不是真的一个问题。
其他提示
你们这些人太有效率了。你真正想要的是:
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;
}
}
[笑话模式= <!>“; off <!>”;
编辑:为枚举添加了令人困惑的值。
响应 ffpf -我完全相同的论据与一位同事多年前,答案是 没有, 它不适用于负数。
C标准规定,负数表示可以在3个方面:
- 2补
- 1的补充
- 签署和幅度
检查这样的:
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编译器一样支持尾递归,它可以有效地实现(变成while / until循环)。在这种情况下,堆栈不应该溢出!
当数除以2时,余数为0时,数字为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;
}
我会建立一个奇偶校验表(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];
}
所以让我们改为使用偶数和奇数的数学定义。
如果存在整数k使得n = 2k,则整数n是偶数。
如果存在整数k使得n = 2k + 1,则整数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表示给定C编译中int
的可能值。 (注意,C-integers是整数的子集。)
现在有人可能会担心,对于C整数中的给定n,相应的整数k可能不存在于C整数中。但是通过一点证明,可以证明对于所有整数n,| n | <!> lt; = | 2n | (*),其中| n |如果n为正,则为<!>; n为n,否则为<!>;换句话说,对于所有n个整数,至少有以下一个成立(事实上恰好是情况(1和2)或情况(3和4),但我不会在这里证明):
案例1:n <!> lt; = 2n。
案例2:-n <!> lt; = -2n。
案例3:-n <!> lt; = 2n。
案例4:n <!> lt; = -2n。
现在取2k = n。 (如果n是偶数,那么确实存在,但我不会在这里证明。如果n不均匀,那么even
中的循环无论如何都无法提前返回,所以无关紧要。)但这意味着k < !> LT; n如果n不是0乘(*)和事实(这里再次证明)对于所有m,整数中的z,2m = z意味着z不等于m给定m不是0.在n为0的情况下,2 * 0 = 0所以0甚至完成(如果n = 0则0为C-整数,因为n在函数odd
中为C-整数,因此k = 0为C-整数)。因此,如果n是偶数,则C-整数中的n存在于n中的n。
类似的论证表明,如果n为奇数,则在C整数中存在k,使得n = 2k + 1.
因此,此处提供的函数<=>和<=>将适用于所有C整数。
// C#
bool isEven = ((i % 2) == 0);
这是一个答案 爪哇:
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;
}
对于3亿个循环,基准时序如下。
3.962 |和面具方法
4.851 <!>放大器;方法
5.850%接近
对于那些认为理论或汇编语言列表的人来说,解决这些论点,这应该是一个警示性的故事。在你的哲学中,天堂和地球上有更多的东西,霍雷肖。
这是一个后续行动的讨论与@RocketRoy关于 他的回答, 但它可能是有用的任何人想来比较这些结果。
tl博士 从我所看到的,罗伊的办法((0xFFFFFFFF == (x | 0xFFFFFFFE)
)是不完全的优化 x & 1
作为 mod
方法,但在实践中运行时应该把平等在所有情况。
因此,首先我比较编制输出用 编译器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));
}
铛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
海湾合作委员会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
帽子下降到铛,它意识到,所有三个案件在功能上是相等的。然而,罗伊的办法不是最优化在海湾合作委员会,所以情况因人而异。
它是类似的用Visual Studio;检查拆卸释放64(VS2015)为这三种功能,我可能看到,比较的部分是平等的"国防部"和"和"情况下,略大于罗伊的"或"情况:
// 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 Studio2005年x86/64,建立释放,没有debugger附件)。
释放组件的使用 test
指令 and
和 mod
情况,而罗伊的情况下使用 cmp eax,0FFFFFFFFh
方法,但它的大量展开,并优化所以没有差异的做法。
我的结果之后20运行(i7 3610QM,Windows10源计划设定为高性能):
[Test: Plain mod 2 ] AVERAGE TIME: 689.29 ms (Relative diff.: +0.000%) [Test: Bitwise or ] AVERAGE TIME: 689.63 ms (Relative diff.: +0.048%) [Test: Bitwise and ] AVERAGE TIME: 687.80 ms (Relative diff.: -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...
}
在<!> quot;广告素材但令人困惑的类别<!>中;我提供:
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
}
}
按位方法取决于整数的内部表示。 Modulo可以在任何模运算符的任何地方工作。例如,某些系统实际上使用低级别位进行标记(如动态语言),因此原始x <!>放大器;在这种情况下,1实际上不起作用。
IsOdd(int x){return true; }
正确性证明 - 考虑所有正整数的集合,并假设存在非空的整数非奇数。因为正整数是有序的,所以会有一个最小而不是奇数,这本身就很奇怪,所以很明显这个数字不能在集合中。因此这个集合不能是非空的。重复负整数,除了寻找最大而非奇数。
便携式:
i % 2 ? odd : even;
不可移植:
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 方法或为什么要使用它?
int isOdd(int i){
return(i % 2);
}
进行。
为了让我们这些在学习期间没有做多布尔代数的人使用按位运算符方法,这里有一个解释。可能对OP没什么用处,但我觉得要明确为什么NUMBER <!> amp; 1作品。
请注意,就像上面有人回答的那样,表示负数的方式可以阻止此方法的工作。实际上,它甚至可以破坏模运算符方法,因为每种语言在处理负操作数方面都有所不同。
但是,如果您知道NUMBER将始终为正,则效果很好。
如上所述Tooony指出,只有二进制(和否定)中的最后一位数字才是重要的。
布尔逻辑AND门指示两个输入必须是1(或高电压),才能返回1。
1 <!> amp; 0 = 0。
0 <!> amp; 1 = 0。
0 <!> amp; 0 = 0。
1 <!> amp; 1 = 1。
如果您将任何数字表示为二进制(我在此处使用了8位表示),则奇数在末尾有1,偶数为0。
例如:
1 = 00000001
2 = 00000010
3 = 00000011
4 = 00000100
如果您取任何数字并使用按位AND(<!> amp;在java中),则它将返回00000001,= 1表示该数字为奇数。或者00000000 = 0,表示数字是偶数。
E.g
奇怪吗?
1 <!> amp; 1 =
00000001 <!> amp;
00000001 =
00000001 <!> lt; <!>#8212;奇
2 <!> amp; 1 =
00000010 <!> amp;
00000001 =
00000000 <!> lt; <!>#8212;甚至
54 <!> amp; 1 =
00000001 <!> amp;
00110110 =
00000000 <!> lt; <!>#8212;甚至
这就是为什么这样做的原因:
if(number & 1){
//Number is odd
} else {
//Number is even
}
很抱歉,如果这是多余的。
Number Zero parity |零 http://tinyurl.com/oexhr3k
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))
<强>输出:强>
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,则为偶数。 在像英特尔的x86架构这样的小端系统上,它将是这样的: -
if (iToTest & 1) {
// Even
} else {
// Odd
}
如果你想要高效,请使用按位运算符(x & 1
),但如果你想要可读,请使用modulo 2(x % 2
)
检查偶数或奇数是一项简单的任务。
我们知道任何可被2整除的数字都是偶数奇数。
我们只需检查任何数字的可分性,并检查可分性,我们使用%
运算符
使用if else检查奇数
if(num%2 ==0)
{
printf("Even");
}
else
{
printf("Odd");
}
使用条件/三元运算符
(num%2 ==0) printf("Even") : printf("Odd");
使用按位运算符
if(num & 1)
{
printf("Odd");
}
else
{
printf("Even");
}
+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 奇怪的 数字。
的 & 按位和操作检查的右边位于我们的 返回 如果这是1
把它想成真与假
当我们比较 n 与 1 这意味着 0001
在二进制(数量的零没关系).
然后让我们来想象一下我们的整数 n 与一种尺寸为1字节。
这将会是由8位/8-二进制数字。
如果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 代表虚假和 T 为真实的。
它的 比较 只有右边位,如果他们俩都是真实的。这样,自动
7 & 1
是 True。
如果有什么我需要检查点之前右边的?
简单地改变 n & 1
要 n & 2
其中2个表示 0010
在二进制等。
我建议使用进制符号如果你是个初学者来bitwise operations
return n & 1;
>> return n & 0x01;
.