Answers:
-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.
输入和输出在程序的开头和结尾是隐式的,因为获取输入和产生输出不是可逆的操作,因此它们不能是命令。
-e "code"
然后在之前插入其他标志e
,例如-pe "code"
。那么该-p
标志仅为一个字节。但是,Stack Cats没有这样的-e
参数,因此您总是需要<sp>-n
在命令中添加完整的内容,因此它是三个字节。
尝试使用高级语言进行此挑战的每个人都错过了真正的机会处理原始位乐趣。做到这一点的方法有很多微妙的变化,这很疯狂,而且思考的乐趣很多。这是我用32位x86汇编语言设计的一些解决方案。
我先向您道歉,这不是典型的代码高尔夫答案。我将大量讨论迭代优化(针对大小)的思考过程。希望这对更多的读者来说是有趣和有教育意义的,但是如果您是TL; DR类型的,那么即使您跳到最后也不会感到冒犯。
一种明显有效的解决方案是测试该值是奇数还是偶数(可以通过查看最低有效位来有效地完成此操作),然后相应地在n + 1或n-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
工作并节省一个字节吗?
-1
。
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>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
.2%?1+:1-
在线尝试!(第二个参数是Braingolf代码,第三个参数是输入)
请参阅上面的说明。唯一的区别是Braingolf v0.2中,diadic运算符的默认行为和,
修饰符的功能被颠倒了,这意味着v0.1答案中不再需要2个逗号。
但是v0.2是在挑战之后发布的,因此这是不竞争的
.1<2,%?+:-
按照我的想法做吗?
-
使它以正确的方式执行操作,在这种情况下,它的长度仍与我的答案相同
<
旋转1
输入下方的内容,以便将其放置在正确的位置。
-
堆栈时看起来像这样:[n,1]
Braingolf运算符被反转,因此它将执行1 - n
,这将导致-(n-1)
期望的结果很简单n-1
<?=-(-$argn^1);
;
需要,并且尝试使用.php
文件并直接回显到php(php7 cli。)中。每次我被告知这$argn
是一个未定义的变量。
F
标志和管道:echo 42 | php -F script.php
。
n=>-(-n^1)
f=
n=>-(-n^1)
i.addEventListener("input",_=>o.innerText=f(+i.value))
<input id=i type=number><pre id=o>
n=>n-1+n%2*2
lambda n:n+(n%2or-1)
n%2or-1
如果为奇数,则返回1,但如果为偶数,n%2
则返回“ false”(0),因此它返回-1。然后,我们只需将其添加到中n
。
lambda n:[n-1,n+1][n%2]
n%2
计算n
除以2 时的余数。如果为偶数,则返回0,此列表中的元素0为n-1
。如果为奇数,则返回1,此列表中的元素1为n+1
。
lambda n:[n-1,n+1][n%2]
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
(({})(())){({}[()]<([{}])>)}{}({}{})
我个人对此感到非常满意,因为它比我认为解决该问题的传统方法要短得多。
代码的第一位
(({})(()))
将堆栈从just转换n
为
n + 1
1
n
然后,当堆栈的顶部不为零时,我们将其递减并翻转其下方的数字的符号
{({}[()]<([{}])>)}
我们删除零并添加剩余的两个数字
{}({}{})
感谢Greg Martin,节省了3个字节!
#-1[-1][[#~Mod~2]]&
#+{-1,1}[[#~Mod~2+1]]&
Mathematica具有很好的功能,例如算术运算会自动遍历列表。
在这种情况下,我们将Mod[#,2]
其返回0或1,但由于Mathematica列表是1索引的,因此需要加1。如果为偶数,则结果为1,因此#-1
返回。如果为奇数,则结果为2,因此#+1
返回。
[[0]]
功能来节省三个字节:#-1[-1][[#~Mod~2]]&
。
n->-(-n^1)
int c(int n){return-(-n^1);}
旧答案:
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
lambda n:n+(n&1)*2-1
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.
piecewise(mod(n,2),1,-1)+n
26 bytes for the function, +1 to enter n
in the parameters box.