Zahlen
Zahlen is a stack-based processor specification discovered by User:Orby during March of 2019 (and revisited during February of 2021). Zahlen is particularly suited toward solving numerical problems in a small amount of space. This page is a work in progress. Many operators are yet undocumented. Please contribute comments and ideas on the discussion page.
Introduction
Zahlen is intended for use in code golf competitions involving numbers. Each Zahlen instruction is represented by an 8-bit code. This makes Zahlen instructions more compact, but also restricts the number of available instructions. The codes 0xA0 through 0xFF are reserved for future expansion.
Types
Zahlen operates on two types: logicals and numericals. Logical values are matrices whose cells are 32-bit unsigned integers. Operations performed on logical values are performed bit-wise. Numerical values are matrices whose cells are IEEE 754 double precision floating point values. In this documentation, matrices are enclosed in brackets.
Opcodes
What follows is a comprehensive list of opcodes.
Unary operators
Each unary operator pops a value from the stack which we refer to here as A. The i,j-th cell of A is referred to as a_{i,j}. The value pushed is dependent upon the type of A and the operator selected. Each operation is named after its effect on a numerical.
Count
Pneumonic: count
If A is not 1 x 1 or a_{1,1} is zero, then the result is undefined.
0x80 | Result |
---|---|
Logical | [ 1, 2, ..., a_{1,1} ] for 1 x 1 matrix A |
Numerical | [ 1, 2, ..., floor(a_{1,1}) ] for 1 x 1 matrix A |
Increment
Pneumonic: inc
0x81 | Result |
---|---|
Logical | [ a_{i,j} + 1 ] |
Numerical | [ a_{i,j} + 1 ] |
Decrement
Pneumonic: dec
0x82 | Result |
---|---|
Logical | [ a_{i,j} - 1 ] |
Numerical | [ a_{i,j} - 1 ] |
Negate
Pneumonic: neg
Alternate pneumonic: not
0x83 | Result |
---|---|
Logical | [ not a_{i,j} ] |
Set | [ -a_{i,j} ] |
Cast
Pneumonic: cast
0x84 | Result |
---|---|
Logical | A as numerical (no precision lost) |
Numerical | A as logical (floor(a_{i,j})) |
Transpose
Pneumonic: trans
0x85 | Result |
---|---|
Logical | [ a_{j,i} ] |
Numerical | [ a_{j,i} ] |
Sign
Pneumonic: sign
0x86 | Result |
---|---|
Logical | [ sign(a_{i,j}) ] |
Numerical | [ sign(a_{i,j}) ] |
Trigonometric functions
These operators all push numerical results.
Sine
Pneumonic: sin
0x87 | Result |
---|---|
Logical | [ a_{i,j} << 1 ] |
Numerical | [ sin(a_{i,j}) ] |
Cosine
Pneumonic: cos
0x88 | Result |
---|---|
Logical | [ a_{i,j} >> 1 ] |
Numerical | [ cos(a_{i,j}) ] |
Binary operators
All binary operators in Zahlen pop two arguments from the stack and push the result. The first argument on the stack is represented as A and its type is provided in the first column of each table. The second argument on the stack is represented as B and its type is provided in the first row of each table. The operation performed depends upon the types of those arguments. Each operation is named after its effect on two numericals. If A is 1 x 1 and B is m x n, then A is expanded to m x n and filled with a_{1,1}.
Addition
Pneumonic: add
Alternate pneumonic: xor
0x8A | Logical | Numerical |
---|---|---|
Logical | [ a_{i,j} xor b_{i,j} ] | [ a_{i,j} + b_{i,j} ] |
Numerical | [ a_{i,j} + b_{i,j} ] | [ a_{i,j} + b_{i,j} ] |
Subtraction
Pneumonic: sub
0x8B | Logical | Numerical |
---|---|---|
Logical | [ a_{i,j} xor b_{i,j} ] | [ a_{i,j} - b_{i,j} ] |
Numerical | [ a_{i,j} - b_{i,j} ] | [ a_{i,j} - b_{i,j} ] |
Multiplication
Pneumonic: mul
0x8C | Logical | Number |
---|---|---|
Logical | [ (a_{i,1} and b_{1,j}) xor (a_{i,2} and b_{2,j}) ... ] | [ (a_{i,1} * b_{1,j}) + (a_{i,2} * b_{2,j}) ... ] |
Numerical | [ (a_{i,1} * b_{1,j}) + (a_{i,2} * b_{2,j}) ... ] | [ (a_{i,1} * b_{1,j}) + (a_{i,2} * b_{2,j}) ... ] |
Pointwise Multiplication
Pneumonic: pmul
Alternate pneumonic: and
0x8D | Logical | Number |
---|---|---|
Logical | [ a_{i,j} and b_{1,j} ] | [ a_{i,j} * b_{i,j} ] |
Numerical | [ a_{i,j} * b_{i,j} ] | [ a_{i,j} * b_{i,j} ] |
Pointwise Division
Pneumonic: pdiv
Alternate pneumonic: or
0x8E | Logical | Numerical |
---|---|---|
Logical | [ a_{i,j} or b_{i,j} ] | [ a_{i,j} / b_{i,j} ] |
Numerical | [ a_{i,j} / b_{i,j} ] | [ a_{i,j} / b_{i,j} ] |
Remainder
Pneumonic: mod
0x8F | Logical | Numerical |
---|---|---|
Logical | [ ] | [ a_{i,j} % b_{i,j} ] |
Numerical | [ a_{i,j} % b_{i,j} ] | [ a_{i,j} % b_{i,j} ] |
Power
Pneumonic: pow
Alternate pneumonic: <<
The notation << denotes left shift.
0x90 | Logical | Numerical |
---|---|---|
Logical | [ a_{i,j} << b_{i,j} ] | [ a_{i,j}^{bi,j} ] |
Numerical | [ a_{i,j}^{bi,j} ] | [ a_{i,j}^{bi,j} ] |
Logarithm
Pneumonic: log
Alternate pneumonic: >>
The notation >> denotes right shift.
0x91 | Logical | Numerical |
---|---|---|
Logical | [ a_{i,j} >> b_{i,j} ] | [ log_{ai,j}(b_{i,j}) ] |
Numerical | [ log_{ai,j}(b_{i,j}) ] | [ log_{ai,j}(b_{i,j}) ] |
Matrix manipulation
These operations are for decomposing and building matrices.
Car
Pneumonic: car
Notice this pushes two results: the first row of A and A with the first row removed.
00x92 | Result |
---|---|
Logical | [ a_{1} ], [ a_{2}, a_{3}, ... ] |
Numerical | [ a_{1} ], [ a_{2}, a_{3}, ... ] |
Cons
Pneumonic: cons
This is the opposite of car. It takes two matrices and concatenates them row-wise. A must have the same number of columns as B.
0x93 | Logical | Numerical |
---|---|---|
Logical | [ A, B ] | [ A, B ] |
Numerical | [ A, B ] | [ A, B ] |
Subroutines
TODO Think about passing a column vector of addresses to call for concurrent function calls.
Call
Pneumonic: call
Opcode: 0x94
Pop A from the stack. If A is 1 x 1, then call the subroutine at a_{1,1}.
Return
Pneumonic: ret
Opcode: 0x95
Return from subroutine.
Ternary operator
Pneumonic: if
Opcode: 0x96
Pops three arguments off the stack A, B, and C.
If A, B, and C are logical then the result is the logical [ (a_{i,j} and b_{i,j}) or (not a_{i,j} and c_{i,j}) ].
If A, B, or C are numerical, then the result is the numerical [ a_{i,j} != 0 ? b_{i,j} : c_{i,j} ]
Memory operators
Store
Pneumonic: st
If A is 1 x 1, then write B sequentially starting at a_{1,1}. Otherwise the dimensions of A and B must match.
0x97 | Result |
---|---|
Logical | Write b_{i,j} to address a_{i,j}. |
Numerical | Write b_{i,j} to address a_{i,j}. |
Load
Pneumonic: ld
0x98 | Result |
---|---|
Logical | Push matrix whose i,j-th cell is the memory contents of address a_{i,j}. |
Numerical | Push matrix whose i,j-th cell is the memory contents of address a_{i,j}. |
Miscellaneous operators
The following operators manipulate the stack and control flow.
Encoding | Pneumonic | Description |
---|---|---|
0x99 | swap | Swap top two arguments on the stack. |
0x9A | drop | Pop the stack, |
0x9B | dup | Duplicate the element on top of the stack. |
0x9C | rot | Pop A. If A is n x 1, then rotate the first a_{1,1} elements of the stack, then rotate the first a_{2,1} elements of the stack, etc. |
0x9D | jz | Pop A. Pop B. If a is 1 x 1 and B does not contain any non-zero values, then set IP to a_{1,1}. |
0x9F X | 128, ..., 65535 | Push 16-bit immediate value to stack as 1 x 1 logical. |
b0xxxxxxx | 0, 1, ..., 127 | Push 7-bit immediate value xxxxxxx to the stack as 1 x 1 logical. |
Examples
Assuming display is 256 x 256 and mapped to the first 65,536 memory addresses in the normal way.
Reverse first n elements on stack
n count rot
3 bytes.
AND pattern
256 ; [ 256 ] count dup ; [ 1, ..., 256 ], [ 1, ..., 256 ] logical column vectors trans mul ; [ x and y ] 0 st ; Write [ x and y ] to 0x00000000
9 bytes.
Extract bits from logical
Suppose a 1 x 1 logical x is on the stack.
32 count sign swap cast pmul cast ; [ x, x, ..., x (32 times) ] 32 count dec cast 2 pow cast ; [ 1, 2, 4, 8, ..., 2^31 ], [ x, x, ..., x (32 times) ] and sign ; [ x[0], x[1], x[2], ..., x[31] ]
15 bytes.
See also
- GolfScript is the canonical golfing language.
- Jelly, Pyth, and CJam are also quite popular.
- FlogScript is an interesting golfing language, too.