在没有比较运算符的情况下比较C或C ++中的两个整数


12

产生最短的程序,该程序将两个有符号整数作为输入(通过stdin或作为参数)并显示3个不同的输出,具体取决于第一个数字是(1)大于,(2)小于还是(3)等于第二个数字数。

赶上

您不能在程序中使用以下任何一项:

  • 该标准比较操作符:<><=>===!=
  • 任何库文件除coniostdioiostream
  • 任何非ASCII或不可打印的ASCII字符。

赢家

字符数最少的程序获胜。


我想也不允许使用abs 包含库文件的东西(因为编译器仍然知道它)?
Martin Ender 2014年

1
@MartinBüttner是的,那是一个正确的假设。:)
格鲁夫

5
为什么限制为C(++)?如果是因为尽管C的基本类型不可移植,但您仍希望答案可移植,则应说明这一点。如果这是一个任意限制,那么您应该知道,对一种语言的任意限制在此站点上并不受欢迎。
彼得·泰勒

8
@PeterTaylor这是挑战的一部分。如果问题与语言无关,那将是完全不同的局面。将其限制为C / C ++可以改变解决问题时所使用的策略。我认识到有必要对大多数语言开放问题,以促进更多人的参与,但是在这个特定问题中,对C / C ++及其特定运算符和方法的限制是挑战的组成部分。
格罗夫2014年

1
@EvilTeach是的;如果问题中未明确禁止任何内容,则允许。
格罗夫2014年

Answers:


2

53个字节

main(a,b){scanf("%d%d",&a,&b);printf("%ld",0l+a-b);}

仅输出的第一个字符是相关的。三种不同的输出是:

  1. 如果b> a,则为“-”
  2. 如果a == b为'0'
  3. 任何其他字符,如果a> b

在sizeof(long)> sizeof(int)的所有平台上,它适用于int的完整输入范围。

编辑:要使情况3唯一地打印一个“ +”,需要花费一个额外的字符:

main(a,b){scanf("%d%d",&a,&b);printf("%+ld",0l+a-b);}

6

也许我遗漏了规则中的某些内容,但是...

81个字节

main(a,b){scanf("%d%d",&a,&b);long long l=a;l-=b;printf("%lld%d",--l>>63,l>>63);}

。OUPUTS 00如果a > b-10如果a == b,和-1-1如果a < b


与这种代码一样常见,C不能保证它能正常工作。long long可能会超过64位,int可能会太大而导致溢出,右移负值的结果由实现定义。几乎所有源自C的答案都有类似的问题。
Yann Vernier 2014年

1
@YannVernier:理解了。我猜测100%的万无一失的解决方案将是一个怪物,因为我们唯一可以安全地做的事情(即不发生移位或溢出)就是摆动,而为了安全地做到这一点,我们需要使用以下方法确定操作数的长度sizeof
COTO 2014年

6

90字节

如果可以使用stdio,为什么不使用其格式化功能进行比较呢?

main(a,b){scanf("%d%d",&a,&b);snprintf(&a,2,"%d",b-a);a&=63;putchar(51-!(a-45)-!!(a-48));}

假定与ASCII兼容的编码和低字节序。

72个字节

商将取整为零,但右移(实际上)为“取整”。那真是太死了。

main(a,b){scanf("%d%d",&a,&b);a-=b;putchar(a?a|=1,a/2-(a>>1)?60:62:61);}

65岁 79个字节

负数的另一个显着特性是它们产生负模。这个根本不依赖于整数表示。它甚至可以在我的8位Extra-127多士炉上使用!哦,既然可以使用了conio,为什么不保存两个字节putch呢?现在,如果我只能找到我的TurboC副本...

main(a,b){scanf("%d%d",&a,&b);long long d=a;d-=b;putch(d?d|=1,d%2-1?60:62:61);}

编辑:处理大差异假设long long比宽int


我很确定您需要在%ds 之间使用定界符scanf来明确解析两个整数。好主意!
Martin Ender 2014年

1
@马丁:嗯,它的工作原理与海湾合作委员会,但我真的不知道,如果是善意的。
2014年

我的意思是,您如何区分输入a = 1, b = 23a = 12, b = 3123两种情况下都不需要戴STDIN吗?
Martin Ender 2014年

1
就像我说的那样,它似乎可以工作(使用1 2312 3作为输入)。
2014年

2
哦,您的输入中确实包含空格。是的,实际上,我对此并不感到惊讶。
Martin Ender 2014年

5

64 61个字符

main(a,b){scanf("%d%d",&a,&b);for(a-=b;a/2;a/=2);putchar(a);}

分别打印小于,等于或大于-1、0和1的字符值。

此实现依赖于b类型int为undefined 且输入范围INT_MIN / 2为to的未定义行为INT_MAX / 2。在有符号溢出环绕的平台上,无论是2s补码(基本上都是2s补码)还是符号幅度,它都会在25%的有效对中失败int。有趣的是(无论如何对我而言),它将在签名溢出饱和的平台上正常工作。


如果a-b溢出,则无法使用。
丹尼斯

遗憾的是,这是事实,但是如果没有比较运算符,我想不出任何平台不可知的方式来避免这种情况。该问题未指定结果必须有效的输入范围。该标准保证此答案适用于所有兼容平台之间-(2^14)以及2^14 - 1在所有兼容平台上的所有输入,并且可能在大多数平台上适用于更大范围的输入。此时所有其他答案都对类型的大小,类型的相对大小或表示形式进行了假设。
laindir 2014年

这个问题说两个有符号整数作为输入,所以我想说它必须适用于所有对。main(a,b)已经是未定义的行为,因此不能保证所有答案都有效。没关系的便携性。
丹尼斯

对于未定义的行为,您绝对是正确的,因此我的实现实际上并不能保证任何标准。我将添加一条注释,指出其局限性。
laindir 2014年

3

66102字节

main(a,b,c,d,e){scanf("%d %d",&a,&b);e=1<<31;c=a&e;d=b&e;putchar(a-b?c&~d?48:d&~c?49:a-b&e?48:49:50);}

从STDIN读取整数并打印0(a <b),1(a> b)或2(a == b)。

编辑:现在它也应该适用于太大而无法容纳32位整数的差异。我敢肯定,嵌套三元数可以通过一些位魔术来缩短。


如果我错了,请纠正我,但在您的内部三元组中看到a <0。
overactor 2014年

@overactor已修复
Martin Ender

3

52个字节

可悲的是,这仅适用于正整数,但我认为使用纯算术运算符的概念很有趣:

main(a,b){scanf("%d%d",&a,&b);putchar(b%a/b-a%b/a);}

输出:

  • ASCII码0xFF:a小于b
  • ASCII码0x00:a等于b
  • ASCII码0x01:a大于b

如果仅使用正整数,putchar(a/b-b/a)则要短很多。
丹尼斯

@Dennis产生不同的输出,例如(50,1)和(51,1)。但是我还是可以缩短一点。
Digital Trauma 2014年

1
是的,我的想法不正确……
丹尼斯

3

 59    54个字符

54个字符,如gcc这样的编译器,它不拒于main(x,y)

main(x,y){scanf("%d%d",&x,&y);y-=x;putchar(y>>31|!y);}

否则为59个字符:

main(){int x,y;scanf("%d%d",&x,&y);y-=x;putchar(y>>31|!y);}

输出:

  • 如果x <y,则ASCII码0x00
  • 如果x> y为ASCII码0xFF
  • 如果x == y,则ASCII码0x01

1
我可以向您保证,main(x,y)可以在gcc中使用,因此请随时从字符数中删除这5个字节。
Martin Ender 2014年

main(x,y)在我的gcc上不起作用。也许需要编译器选项。但是您可以将main(x,y)替换为x; main(y)。
Florian F

2

66个字节

main(a,b){scanf("%d%d",&a,&b);putchar((0l+b-a>>63)-(0l+a-b>>63));}

如果输出字节0x00,则输出a == b0x01,如果输出a < b0xff a > b

由于[my]程序中的非ASCII或不可打印的ASCII字符,并且如果问题中未明确禁止任何内容,则允许这样做,因此输出中不可打印的字符应完全正确。


我以前的版本不能很好地处理溢出。这适用于long64位的x64 Linux 。
丹尼斯2014年

2

87个字符

main(a,b,c){scanf("%d%d",&a,&b);c=1<<31;a+=c;b+=c;puts(a^b?(unsigned)a/b?">":"<":"=");}

使用2 ^ 31技巧转换为unsigned int

将除法强制转换为无符号,以将高位作为数据而不是符号处理

使用^对a和b进行异或运算,当它们相等时返回0

使用嵌套条件(?)来获取“ <”,“>”或“ =”以提供给puts()


1

71个字节

main(x,y,z){scanf("%d%d",&x,&y);putchar((z=x-y)?(z&(z>>31))?50:49:51);}

http://ideone.com/uvXm6c


您的ideone周围有括号z=x-y,我很确定它们是必需的。您也可以直接使用49, 50` 保存两个字符51,而不用添加48
Martin Ender 2014年

分配的优先级低于三元运算符:en.cppreference.com/w/c/language/operator_precedence
Martin Ender

上面的代码缺少分号,并且对于-2000000000 2000000000,以及导致减法溢出的整数的任何其他组合,均失败。
COTO 2014年

1

68个字符

int main(a,b){scanf("%d%d",&a,&b);putchar(a-b?((unsigned)a-b)>>31:2);}

将ASCII字符1、2或3分别放置为小于,大于或等于。


1
如果a-b溢出,则无法使用。
丹尼斯

1

88 89字节

main(a,b){scanf("%d%d",&a,&b);a+=1<<31;b+=1<<31;for(;a&&b;a--)b--;putchar(a?b?48:49:50);}

首先在1<<31INT_MINa)和(b)上加上(),现在0对应INT_MIN。然后循环并递减a和b直到每次循环为0,然后根据a,b或两者均为0来打印0、1或2。

120个 119字节

main(a,b,c){scanf("%d%d",&a,&b);c=1<<31;a^=c;b^=c;for(c~=c;!c;c/=2)if(a&c^b&c){putchar(a?48:49);return;}putchar(50);}

这不是最短的解决方案,但可能比我更好的高尔夫球手打了一点球。(或者只是比我更了解C的人)

这个想法是屏蔽每个位,从左边开始,并检查不等式。其余的应该自己解释。由于负数以1位开始,因此我首先用反转第一位a^=1<<31


我暂时无法测试我的解决方案,请随时指出错误。
overactor 2014年

第一个解决方案有两个问题:1.快乐的;)笑脸应该是悲伤的);笑脸。2. a&b仅测试ab是否具有相同的位;你需要&&
丹尼斯

@丹尼斯,你是对的,谢谢。
overactor

1

我想我什至不会尝试编写短代码。我将尝试以按照C99规范可移植的方式执行此比较。

int a, b;   // Let's assume these are initialized
int sign_a = a ? ((a|7)^2)%2 + ((a|7)^3)%2 : 0;

模运算符保留符号,但它很可能会产生零(包括负零),因此我们确保要检查它具有奇数和偶数(即使不知道我们是否使用补数)。算术运算可能会溢出,但按位运算不会溢出,通过确保同时设置和清除了一些位,我们避免了无意中将数字转换为负零或陷阱值的情况。奇怪的是,需要执行两个操作这一事实无关紧要,因为可能的陷阱表示在放入左值之前不会引起未定义的行为。切换位0来执行操作可确保我们得到恰好一个非零的余数。有了两个信号的知识,我们就可以决定如何进行比较。

char result="\0<<>=<>>\0"[4+3*sign_a+sign_b]
if (!result) {   // signs matching means subtraction won't overflow
  int diff=a-b;
  int sign_diff=diff ? (diff|7^2)%2 + (diff|7^3)%2 : 0;
  result = ">=<"[1-sign_diff];
}

此方法可能是允许提取整数负零的正负号的几种方法之一。我们通过显式检查零来解决该问题。如果我们真正打高尔夫,我们当然可以允许两个零的比较也执行减法。


1

C 80个字符

a,b,c=1<<31;main(){scanf("%d%d",&a,&b);putchar(a^b?(a&c^b&c?a:a-b)&c?60:62:61);}

它会按要求打印“ <”,“>”或“ =”。

C 63个字符

一种新方法:

a;main(b){scanf("%d%d",&a,&b);putchar(50+(0L+a-b>>42)+!(a-b));}

打印“ 1”,“ 2”或“ 3”。


1

不带stdio.h的64个字符

a,b;main(){scanf("%d%d",&a,&b);puts((a-b)>>31?"<":a^b?">":"=");}

如果a> b,则输出'>';如果a <b,则输出'<';如果a == b,则输出'='。int溢出为UB。只是不要溢出。

// declare a and b as ints
a,b;

// defaults to int
main()
{
  scanf("%d%d",&a,&b);
   /*
    * (a-b)>>31 signbit of a-b
    * a^b a xor b -> 0 if they are equal
    */
  puts(((a-b)>>31) ? "<" : (a^b) ? ">" : "=");
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.