交换平价


22

任务

给定正整数n,则输出n+1if n为奇数,输出n-1if n为偶数。

输入项

一个正整数。您可以假定该整数在该语言的处理能力范围内。

输出量

正整数,如上所述。

测试用例

input output
    1      2
    2      1
    3      4
    4      3
    5      6
    6      5
    7      8
    8      7
  313    314
  314    313

计分

这是,因此最短答案以字节为单位。

有标准漏洞

参考文献


我们可以将输入作为一元吗?
Kritixi Lithos'5

2
令人惊讶的是,如果这在某些语言中是
相反的

3
@MistahFiggins众所周知,我很确定OP是故意这样做的。
与Orjan约翰森

Answers:


24

C,20个字节

f(x){return-(-x^1);}

在线尝试


7
@LeakyNun我不是在编写缺少return语句的函数。
feersum

18
@EriktheOutgolfer号,不。嗯 编号
-feersum

10
@Sisyphus但这是代码高尔夫,它可以在我的TIO链接上使用,因此有效。
暴民埃里克(Erik the Outgolfer)'17年

7
@EriktheOutgolfer我的意思是您的陈述(“分配给第一个参数等效于return陈述”)实际上是不正确的。这样的代码在某些情况下是否可以产生有效的答案是另一个问题(我在第一条评论中已经指出,我计划不发布任何这样的代码)。
feersum

8
@EriktheOutgolfer如果答案取决于特定于实现的行为,则应指定一个实现。这个答案没有,所以代码将是无效的。
西西弗斯(Sisyphus)

17

堆叠猫,3 + 3(-n)= 6字节

-*-

在线尝试!

需要 -n标志与数字输入和输出一起使用。

说明

Stack Cats通常没有竞争力,这是因为它的命令集有限(所有命令都是注入命令,而大多数是内卷运算),并且每个程序都必须具有镜像对称性。但是,对合运算之一是切换数字的最低有效位,我们可以用也存在的一元否定值来抵消该值。幸运的是,这为我们提供了一个对称程序,因此我们无需担心其他任何事情:

-   Multiply the input by -1.
*   Toggle the least significant bit of the value (i.e. take it XOR 1).
-   Multiply the result by -1.

输入和输出在程序的开头和结尾是隐式的,因为获取输入和产生输出不是可逆的操作,因此它们不能是命令。


1
标记是否总是用额外的空间计算出来的,我认为我没有看到使用标记(例如Perl)的其他答案吗?编辑:确定nvm,找到相关的元帖子。“ 我把那些算作没有它们的最短等效调用的字符数之差。 ” ...“ perl -nle 'stuff'比2个字符多2个字符perl -e 'stuff',因此它算作另外2个字符 ”。所以(space)-n比没有标志多3个字节。
凯文·克鲁伊森

@KevinCruijssen这取决于您实际上需要向通常的调用中添加多少个字节。在Perl和许多其他生产语言中,您可以使用调用代码,-e "code"然后在之前插入其他标志e,例如-pe "code"。那么该-p标志仅为一个字节。但是,Stack Cats没有这样的-e参数,因此您总是需要<sp>-n在命令中添加完整的内容,因此它是三个字节。
马丁·恩德

12

x86 Assembly,9个字节(用于竞争条目)

尝试使用高级语言进行此挑战的每个人都错过了真正的机会处理原始位乐趣。做到这一点的方法有很多微妙的变化,这很疯狂,而且思考的乐趣很多。这是我用32位x86汇编语言设计的一些解决方案。

我先向您道歉,这不是典型的代码高尔夫答案。我将大量讨论迭代优化(针对大小)的思考过程。希望这对更多的读者来说是有趣和有教育意义的,但是如果您是TL; DR类型的,那么即使您跳到最后也不会感到冒犯。

一种明显有效的解决方案是测试该值是奇数还是偶数(可以通过查看最低有效位来有效地完成此操作),然后相应地在n + 1n-1之间进行选择。假设输入作为参数在ECX寄存器中传递,并且结果在EAX寄存器中返回,我们得到以下函数:

F6 C1 01  |  test  cl, 1                      ; test last bit to see if odd or even
8D 41 01  |  lea   eax, DWORD PTR [ecx + 1]   ; set EAX to n+1 (without clobbering flags)
8D 49 FF  |  lea   ecx, DWORD PTR [ecx - 1]   ; set ECX to n-1 (without clobbering flags)
0F 44 C1  |  cmovz eax, ecx                   ; move in different result if input was even
C3        |  ret

(13个字节)

但是出于代码高尔夫球的目的,这些LEA指令并不是很好,因为它们需要3个字节来进行编码。一个简单的DEC语句ECX会短得多(只有一个字节),但这会影响标志,因此我们在代码的排列方式上必须比较聪明。我们可以做减量第一,和奇/偶试第二,但我们有反转奇/偶试验的结果。

另外,我们可以将条件移动指令更改为分支,这可能会使代码运行得更慢(取决于分支的可预测性-如果输入在奇数和偶数之间不一致地交替变化,则分支将变慢;如果存在模式,速度会更快),这将为我们节省另一个字节。

实际上,通过该修订版,整个操作可以仅使用单个寄存器就地完成。如果您在某个地方内联此代码,那将是很棒的(而且由于它太短了,所以可能会这样)。

    48     |  dec  eax          ; decrement first
    A8 01  |  test al, 1        ; test last bit to see if odd or even
    75 02  |  jnz  InputWasEven ; (decrement means test result is inverted)
    40     |  inc  eax          ; undo the decrement...
    40     |  inc  eax          ; ...and add 1
  InputWasEven:                 ; (two 1-byte INCs are shorter than one 3-byte ADD with 2)

(内联:7个字节;作为功能:10个字节)

但是,如果您确实想使其具有功能怎么办?没有标准的调用约定使用与返回值相同的寄存器来传递参数,因此您需要MOV在函数的开头或结尾添加一个register-register 指令。这实际上没有速度上的代价,但是确实增加了2个字节。(该RET指令还添加了一个字节,由于需要进行函数调用和从函数调用返回而引入了一些开销,这意味着这是一个示例,其中内联既带来了速度大小上的好处,又不仅仅是传统的速度(对于空间的权衡。)总的来说,作为一个函数编写的这段代码膨胀到10个字节。

10字节还可以做什么?如果我们完全关心性能(至少是可预测的性能),那么摆脱该分支将是很好的。这是一个无分支的,比特混乱的解决方案,大小相同,以字节为单位。基本前提很简单:我们使用按位XOR翻转最后一位,将奇数值转换为偶数值,反之亦然。但是有一个小问题-对于奇数输入,给我们n-1,而对于偶数输入,给我们n + 1-与我们想要的恰好相反。因此,要解决此问题,我们将对负值执行运算,从而有效地翻转符号。

8B C1     |  mov eax, ecx   ; copy parameter (ECX) to return register (EAX)
          |
F7 D8     |  neg eax        ; two's-complement negation
83 F0 01  |  xor eax, 1     ; XOR last bit to invert odd/even
F7 D8     |  neg eax        ; two's-complement negation
          |
C3        |  ret            ; return from function

(内联:7个字节;作为功能:10个字节)

光滑 很难看到如何对其进行改进。不过,有一件事引起了我的注意:这两个2字节NEG指令。坦率地说,两个字节似乎太多了,无法编码一个简单的否定,但这就是我们必须使用的指令集。有什么解决方法吗?当然!如果我们XOR加-2,我们可以用第二个NEG语句代替第二个INC语句:

8B C1     |  mov eax, ecx
          |
F7 D8     |  neg eax
83 F0 FE  |  xor eax, -2
40        |  inc eax
          |
C3        |  ret

(内联:6个字节;作为功能:9个字节)

x86指令集的另一个奇特之处是多用途LEA指令,它可以在单个指令中执行寄存器-寄存器移动,寄存器-寄存器加法,偏移量常量以及全部缩放!

8B C1        |  mov eax, ecx
83 E0 01     |  and eax, 1        ; set EAX to 1 if even, or 0 if odd
8D 44 41 FF  |  lea eax, DWORD PTR [ecx + eax*2 - 1]
C3           |  ret

(10个字节)

AND指令类似于TEST我们之前使用的指令,两者都执行按位与并相应地设置标志,但AND实际上更新了目标操作数。所述LEA然后指令由2缩放此,由1增加了原来的输入值,并且递减如果输入值是奇数时,此减去1 -从它(2×0 1 = -1); 如果输入值是偶数,则将其加1(2×1 − 1 = 1)。

这是一种非常快速有效的代码编写方式,因为很多执行都可以在前端完成,但是用字节的方式并不会给我们带来太大的麻烦,因为编码一个复杂的代码需要花费很多。 LEA指令。此版本也不能很好地用于内联,因为它要求将原始输入值保留为LEA指令的输入。因此,在最后一次优化尝试之后,我们实际上倒退了,这表明可能是时候停止了。


因此,对于最后的竞争条目,我们有一个9字节的函数,该函数将ECX寄存器中的输入值(在32位x86上基于半标准的基于寄存器的调用约定)取回,并将结果返回到EAX寄存器中(如所有x86调用约定):

           SwapParity PROC
8B C1         mov eax, ecx
F7 D8         neg eax
83 F0 FE      xor eax, -2
40            inc eax
C3            ret
           SwapParity ENDP

准备与MASM组装;来自C的呼叫为:

extern int __fastcall SwapParity(int value);                 // MSVC
extern int __attribute__((fastcall)) SwapParity(int value);  // GNU   

不仅可以dec eax; xor eax, 1; inc eax工作并节省一个字节吗?
Ilmari Karonen'5


11

Python3,20 18个字节

lambda n:n-1+n%2*2

很简单 首先,我们计算n-1并决定是否将其加2。

如果n是偶数 -> n mod 2将为0,因此我们将2 * 0加到n-1,得到n-1

如果n是奇数 -> n mod 2将为1,因此我们将2 * 1加到n-1上,得到n + 1

我更喜欢用MS Paint和笔记本电脑触摸板做出的解释... Visual explanation


10

Python,16个字节

lambda x:-(-x^1)

在线尝试!


3
在中,使用字符无法进行蛮力逼迫"x+-012~|&^()*/%"
xnor

@xnor好东西,我明白了!
sagiksp

1
看起来,除了琐碎的重排之外,没有其他相同长度的解决方案-(1^-x)
xnor

8

MATL,7个字节

Q:HePG)

这避免了任何算术运算。在线尝试!

说明

以输入4为例。

Q    % Implicit input. Add 1
     % STACK: 5
:    % Range
     % STACK: [1 2 3 4 5]
He   % Reshape with 2 rows in column-major order. Pads with a zero if needed
     % STACK: [1 3 5;
               2 4 0]
P    % Flip vertically
     % STACK: [2 4 0;
               1 3 5]
G    % Push input again
     % STACK: [2 4 0;
               1 3 5], 4
)    % Index, 1-based, in column major order. Implicitly display
     % STACK: 3

1
真好!喜欢它 !
Stewie Griffin's

6

Braingolf V0.111 10个字节

.1>2,%?+:-

在线尝试!(第二个参数是Braingolf代码,第三个参数是输入)

感谢尼尔节省了一个字节

有史以来第一个竞争的脑高尔夫答案:D

说明:

.            Duplicate the top of the stack
 1>          Push 1 to the bottom of the stack
   2         Push 2 to stack
    ,%       Pop last 2 items, mod them and push result
      ?      If last item > 0
       +     Add the 1 to the input
        :    Else
         -   Subtract the 1 from the input

             No semicolon in code so print last item

Braingolf v0.2,9个字节[非竞争]

.2%?1+:1-

在线尝试!(第二个参数是Braingolf代码,第三个参数是输入)

请参阅上面的说明。唯一的区别是Braingolf v0.2中,diadic运算符的默认行为和,修饰符的功能被颠倒了,这意味着v0.1答案中不再需要2个逗号。

但是v0.2是在挑战之后发布的,因此这是不竞争的


5
恭喜您使用了新语言!
Leaky Nun

.1<2,%?+:-按照我的想法做吗?
尼尔

@Neil不太清楚,您需要在逗号之前-使它以正确的方式执行操作,在这种情况下,它的长度仍与我的答案相同
Skidsdev

@Mayube我期望<旋转1输入下方的内容,以便将其放置在正确的位置。
尼尔

@Neil如果输入是偶数,则在到达-堆栈时看起来像这样:[n,1]Braingolf运算符被反转,因此它将执行1 - n,这将导致-(n-1)期望的结果很简单n-1
Skidsdev

5

Cubix10 9字节

cO1)I(//@

在线尝试

说明

网络版

    c O
    1 )
I ( / / @ . . .
. . . . . . . .
    . .
    . .

执行的字符是

I(1c)O@
I          Input
 (         Decrement
  1c       XOR with 1
    )      Increment
     O@    Output and exit

4

Python,68个字节

lambda x:[m.floor(x-m.cos(m.pi*x)) for m in [__import__('math')]][0]

本着独特的精神。下图显示了该功能(紫色的圆点代表前10种情况)。从理论上讲,应该有可能基于大多数(全部?)周期函数(例如sin,tan,sec)构造该问题的解决方案。实际上,按原样在代码中用co代替sec应该可以。

Graph demonstrating function


3

PHP,15个字节

<?=-(-$argn^1);

2
我该如何运行?我正在尝试测试是否;需要,并且尝试使用.php文件并直接回显到php(php7 cli。)中。每次我被告知这$argn是一个未定义的变量。
Andrakis'5

2
@Andrakis带有F标志和管道:echo 42 | php -F script.php
user63956 '17

3

Javascript,17个12字节

x=>x-(-1)**x

f=x=>x-(-1)**x;
<input id=i oninput=o.innerText=f(this.value) type=number><pre id=o>

另一种方法,从C答案(sssshhh)中窃取了 10个字节

x=>-(-x^1)

f=x=>-(-x^1)
<input id=i oninput=o.innerText=f(this.value) type=number><pre id=o>


1.不需要包含分号;2.x=>x-(-1)**x
Leaky Nun

为什么|0呢?两种解决方案似乎都应该将字符串自动转换为数字。(对于第一个解决方案,如果要避免使用小数,请使用<input type=number>。)
Neil

@Neil感谢您通知我!
马修·卢

3

JavaScript(ES6),14 13 12 10字节

n=>-(-n^1)
  • 感谢Luke节省了1个字节。
  • 移植feersum的C解决方案可节省2个字节。(如果对此不满意,请让我知道,我将在下面回滚到以前的解决方案)

试试吧

f=
n=>-(-n^1)
i.addEventListener("input",_=>o.innerText=f(+i.value))
<input id=i type=number><pre id=o>


原始的12个字节

n=>n-1+n%2*2

2

Python,20个字节

lambda n:n+(n%2or-1)

n%2or-1如果为奇数,则返回1,但如果为偶数,n%2则返回“ false”(0),因此它返回-1。然后,我们只需将其添加到中n

先前的解决方案,23个字节

lambda n:[n-1,n+1][n%2]

n%2计算n除以2 时的余数。如果为偶数,则返回0,此列表中的元素0为n-1。如果为奇数,则返回1,此列表中的元素1为n+1


1
使用lambda:lambda n:[n-1,n+1][n%2]
Leaky Nun

是的,因此在这种情况下它更短。完成,谢谢!
numbermaniac

2

视网膜,21字节

.+
$*
^11(?=(11)*$)


在线尝试!我的第一个Retina回答是两个结尾的换行符!说明:前两行从十进制转换为一元。第三和第四行从偶数中减去两个。最后一行转换回十进制,但也加一。



2

库比克斯,11个字节

u%2!I(/+@O<

在线尝试!

说明

网络版本:

    u %
    2 !
I ( / + @ O < .
. . . . . . . .
    . .
    . .

字符按以下顺序执行:

I(2%!+O@
I        # Take a number as input
 (       # Decrement it
  2%     # Take the parity of the decremented number
         # (0 if the input is odd, 1 if it's even)
    !    # If that number is zero:
     +   #   Add 2
      O  # Output the number
       @ # Terminate the program

2

Brain-Flak,36个字节

(({})(())){({}[()]<([{}])>)}{}({}{})

在线尝试!

我个人对此感到非常满意,因为它比我认为解决该问题的传统方法要短得多。

说明

代码的第一位

(({})(()))

将堆栈从just转换n

n + 1
  1
  n

然后,当堆栈的顶部不为零时,我们将其递减并翻转其下方的数字的符号

{({}[()]<([{}])>)}

我们删除零并添加剩余的两个数字

{}({}{})

2

Mathematica,22个 19字节

感谢Greg Martin,节省了3个字节!

#-1[-1][[#~Mod~2]]&

上一个答案,22个字节

#+{-1,1}[[#~Mod~2+1]]&

说明(先前的答案)

Mathematica具有很好的功能,例如算术运算会自动遍历列表。

在这种情况下,我们将Mod[#,2]其返回0或1,但由于Mathematica列表是1索引的,因此需要加1。如果为偶数,则结果为1,因此#-1返回。如果为奇数,则结果为2,因此#+1返回。


2
您可以通过滥用Mathematica的[[0]]功能来节省三个字节:#-1[-1][[#~Mod~2]]&
格雷格·马丁

太疯狂了,从来没有想过。完成,谢谢!
numbermaniac '17

2

明智的 8字节

-::^~-^-

在线尝试!

说明

如果这是相反的方法(如果为奇数则减少,如果为偶数则增加),这将非常容易。

我们只需要翻转最后一点。

::^~-^

此处的解决方法是,当负数时我们将最后一位翻转。负数与负数之差为1,~因此这产生了偏移来解决问题。

因此,我们只需要取出程序并将其包装在中即可-

-::^~-^-

1

Java 8,16 10字节

n->-(-n^1)

Java 7,34 28字节

int c(int n){return-(-n^1);}

@feersum令人惊叹的C答案很无聊。
在这里尝试。


旧答案:

Java 8,16字节

n->n%2<1?n-1:n+1

Java 7,34个字节

int c(int n){return--n%2>0?n:n+2;}

说明(旧的Java 7答案):

在这里尝试。

上面的答案是int c(int n){return n%2<1?n-1:n+1;}通过消除空间的一个较短的变体。

int c(int n){     // Method with integer parameter and integer return-type
  return--n%2>0?  //  If n-1 mod-2 is 1:
    n             //   Return n-1
   :              //  Else:
    n+2;          //   Return n+1
}                 // End of method



1

Befunge 93, 18 bytes

&:2%#v_1+.@
@.-1 <

I am not done golfing this yet (I hope).


Golfing tips: Befunge 98 has the ability to use kv (or jv if it is strictly 1 or 0) instead of #v_. Also, if you are using Try it online (and I recommend it), you can end the program with another & (although it will take 60 seconds), so you can get rid of the @ on the first line if you use that. here is the full list of commands for Befunge-98, although they might not all be correctly implemented in TIO, like & ending the program instead of reversing on EOF.
MildlyMilquetoast

Also, It looks like you're using befunge 93 instead of 98, which has fewer commands. You might want to fix your link name if it is indeed 93 and not 98
MildlyMilquetoast

@MistahFiggins, ah yes you are correct I was using 93.
Daniel


1

R, 17 bytes

(n=scan())-(-1)^n

where n=scan() takes the digit value.


I think you need -(-1)^n rather than +(-1)^n since we need to return n-1 if n is even
Giuseppe

@Giuseppe oh, yes, of course, foolish mistake
Nutle

1

Casio-Basic, 27 bytes

piecewise(mod(n,2),1,-1)+n

26 bytes for the function, +1 to enter n in the parameters box.




0

Batch, 20 bytes

@cmd/cset/a"-(1^-%1)

Independently rediscovered @feersum's algorithm, honest!

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.