I don't even... I only odd!
Lenguage, 645529908926937253684695788965635909332404360034079 9394157991500940492270727190763049448735 1174269748937617561533841898064735499551 2293382937520069758100171520285996319 bytes
That's roughly equal to 2 duodecillion bytes.
The file translates to the following brainfuck program:
,[<<+>+>-]<[>>+<<-]+>>[-[->]<]<[<[<]>.<]
Takes input as an ASCII code, with a maximum value of 256. Uses wrapping.
x86-64 Machine Code, 8 bytes
Inspired by Bruce Forte's solution, but slightly under par. :-)
8D 07 lea eax, [rdi] ; put copy of input parameter in EAX
D1 EF shr edi, 1 ; shift LSB into CF
InfiniteLoop:
F3 73 FD rep jnc InfiniteLoop ; test CF; infinite loop back here if input was even
C3 ret ; return with original input in EAX if it was odd
A single integer parameter is taken in the EDI
register, following the System V AMD64 calling convention.
A copy of this value is initially made, and put into EAX
so it can be returned if appropriate. (LEA
is used instead of the normal MOV
because we need an instruction with odd bytes.)
Then, the value in EDI
is shifted right by 1, which places the shifted-off bit into the carry flag (CF). This bit will be 0 if the number was even, or 1 if it was odd.
We then test CF using the JNC
instruction, which will branch only if CF is 0 (i.e., the number was even). This means that we will go into an infinite loop for even values. For odd values, we fall through and the original value (in EAX
) is returned.
There is a bit of a trick with the JNC
instruction, though—it has a REP
prefix! Normally, REP
prefixes are only used with string instructions, but because the Intel and AMD manuals both agree that irrelevant/superfluous/redundant REP
prefixes are ignored, we throw one on the branch instruction here to make it 3 bytes long. That way, the relative offset that gets encoded in the jump instruction is also odd. (And, of course, REP
is itself an odd-byte prefix.)
Thank goodness RET
is encoded using an odd byte!
Try it online!
In case you don't think returning the value if it's odd or going into an infinite loop if it's even (so that you never return) satisfies the "output" requirements of the challenge, or you just want something more interesting, here's a function that outputs the value to a serial port (but only if it's odd, of course).
x86-64 Machine Code (output to serial port), 17 bytes
8D 07 lea eax, [rdi] ; put copy of input parameter (EDI) in EAX
B1 F7 mov cl, 0xf7 ; put 0xF7 into low-order bits of CX
B5 03 mov ch, 0x03 ; put 0x03 into high-order bits of CX
FE C1 inc cl ; increment low-order bits of CX to 0xF8 (so all together it's now 0x3F8)
0F B7 D1 movzx edx, cx ; move CX to DX ("MOV DX, CX" would have a 16-bit prefix of 0x66)
D1 EF shr edi, 1 ; shift LSB of input parameter into CF
73 01 jnc IsEven ; test CF: branch if 0 (even), fall through if 1 (odd)
EF out dx, eax ; output EAX (original input) to I/O port 0x3F8 (in DX)
IsEven:
C3 ret ; return
What makes this a bit more interesting is that the code does more, which means it was more challenging to do it all using instructions that are encoded using only odd bytes. Of course, this also means that it fails at code golf, so it's kind of a tradeoff—do you want interesting and challenging, or do you want short?
Anyway, this uses the x86 OUT
instruction to write to I/O port 0x3F8, which is the standard COM1 serial port on a PC. The fun part, of course, is that all standard I/O ports (serial and parallel) have even addresses, so they can't simply be encoded as immediates for the OUT
instruction or moved directly into a register. You have to initialize with one less than the actual value, and then increment the value in the register. You're also limited to using certain registers for the manipulation because you need registers that are encoded using odd bytes in the instruction when used as operands.
Also, I had to initialize the DX
register (via the CX
register) at the top of the loop, even though this is only needed if the value is odd, to ensure that the JNC
instruction would have an odd offset. However, since what we're skipping over is the OUT
instruction, all this code does is waste cycles and clobber scratch registers; it doesn't actually output anything, so it doesn't break the rules.
Finally, this function will return (after having either done or not done the output to the serial port) with the input value left in EAX
. But that doesn't actually break any rules; all functions in assembly language will return with a value in EAX
—the question is just is it a significant value or a garbage value. That's determined by the function's documentation (essentially, does it return a value or does it return void
), and in this case, I'm documenting it as not returning a value. :-)
No TIO link for this one, as it doesn't implement output to serial ports. You'll need real iron, or an imagination.
Jelly, 2 bytes
ẋḂ
These characters correspond to bytes 0xF7 and 0xBF in Jelly's code page.
Try it online!