Skip to content

Fingerprints

Thomas Jollans edited this page Nov 13, 2021 · 4 revisions

Fingerprints implemented by RFunge

For each fingerprint, the original source is listed, followed by the original documentation, followed by any addenda or notes on ambiguities or implementation details.

"BOOL" 0x424F4F4C ‘Logic functions’

From the rcFunge docs

Instruction Args Description
A (a b — r) And
N (a — r) Not
O (a b — r) Or
X (a b — r) Xor

Addendum: These ‘logic‘ functions are bitwise operations.

"FIXP" 0x4649585 ‘Some useful fixed point math functions’

From the rcFunge docs

Instruction Args Description
A (a b — a and b) And
B (n — arccos(b)) Find arccosin of tos
C (n — cos(b)) Find cosin of tos
D (n — rnd(n)) RanDom number
I (n — sin(b)) Find sin of tos
J (n — arcsin(b)) Find arcsin of tos
N (a — 0-a) Negate
O (a b — a or b) Or
P (a — a*pi) Multiply by pi
Q (a — sqrt(a)) Square root
R (a b — a**b) Raise a to the power of b
S (n — n) Replace tos with sign of tos
T (n — tan(b)) Find tangent of tos
U (n — arctan(b) Find arctangent of tos
V (n — n) Absolute value of tos
X (a b — a xor b) Xor
  • The functions C,I,T,B,J,U expect their arguments times 10000, for example: 45 should be passed as 450000. The results will also be multiplied by 10000, thereby giving 4 digits of decimal precision.
  • Trigonometric functions work in degrees. not radians.

"FPDP" 0x46504450 ’Double precision floating point’

From the rcFunge docs

Instruction Args Description
A (a b — n) Add two double precision fp numbers
B (n — n) Sin of double precision fp number
C (n — n) Cosin of double precision fp number
D (a b — n) Divide two double precision fp numbers
E (n — n) Arcsin of double precision fp number
F (n — n) Convert integer to floating point
G (n — n) Arctangent of double precision fp number
H (n — n) Arccosin of double precision fp number
I (n — n) Convert floating point to integer
K (n — n) Natural logarithm of double precision fp number
L (n — n) Base 10 logarithm of double precision fp number
M (a b — n) Multiply two double precision fp numbers
N (n — n) Negate double precision fp number
P (n — ) Print a floating point number
Q (n — n) Double precision square root
R (0gnirts — n) Convert ascii number to floating point
S (a b — n) Subtract two double precision fp numbers
T (n — n) Tangent of double precision fp number
V (n — n) Absolute value of double precision fp number
X (n — n) Exponential of double precision fp number (e**n)
Y (x y — n) Raise x to the power of y

Addendum: The docs do not mention whether these instructions operate on one or two stack cells per double. De facto, all interpreters use two cells per double; rfunge does so too, even in 64-bit mode (where a double could fit in a single cell)

Trig functions work in radians (like FPSP, unlike FIXP)

"FPRT" 0x46505254 ‘Formatted print’

From the rcFunge docs

Instruction Args Description
D (fmt fh fl — 0gnirts) Format FPDP type number
F (fmt f — 0gnirts) Format FPSP type number
I (fmt i — 0gnirts) Format an integer
L (fmt h l — 0gnirts) Format a long integer
S (fmt 0gnirts — 0gnirts) Format a string

Formats are printf style. Error in any function reflects.

Addendum: Format strings are 0gnirts. Only exactly one conversion is supported per format string, passing a format string with no valid fields or with too many is undefined behaviour. All standard C99 formats should be supported in theory, but sometimes aren't.

"FPSP" 0x46505350 ‘Single precision floating point’

From the rcFunge docs

Instruction Args Description
A (a b — n) Add two single precision fp numbers
B (n — n) Sin of single precision fp number
C (n — n) Cosin of single precision fp number
D (a b — n) Divide two single precision fp numbers
E (n — n) Arcsin of single precision fp number
F (n — n) Convert integer to floating point
G (n — n) Arctangent of single precision fp number
H (n — n) Arccosin of single precision fp number
I (n — n) Convert floating point to integer
K (n — n) Natural logarithm of single precision fp number
L (n — n) Base 10 logarithm of single precision fp number
M (a b — n) Multiply two single precision fp numbers
N (n — n) Negate single precision fp number
P (n — ) Print a floating point number
Q (n — n) Single precision square root
R (0gnirts — n) Convert ascii number to floating point
S (a b — n) Subtract two single precision fp numbers
T (n — n) Tangent of single precision fp number
V (n — n) Absolute value of single precision fp number
X (n — n) Exponential of single precision fp number (e**n)
Y (x y — n) Raise x to the power of y

Trig functions work in radians

"FRTH" 0x46525448 ‘Some common forth commands’

From the rcFunge docs

Instruction Args Description
D ( — n) Push depth of stack to tos
L (… n — …) Forth Roll command
O (a b — a b a) Forth Over command
P (… n — …) Forth Pick command
R (a b c — b c a) Forth Rot command

Stack operations are subject to the modes set by MODE

Clarification

  • P should reflect on a negative argument
  • P should push 0 if argument is greater than stack size
  • L should act like forth -roll with a negative argument
  • L with an argument larger than the stack size is allowed, enough zeroes will be created in order to fulfill the request. Example: n543210a-L will leave a stack of: 2 3 4 5 0 0 0 0 0 0 1
  • L, P: the top of stack is position 0

Addendum: Note that L with negative argument is implemented as described in rcFunge and rfunge, but not in several other implementations of the fingerprint.

"HRTI" 0x48525449 ‘High-Resolution Timer Interface’

From the catseye library (‘Under development.’)

The HRTI fingerprint allows a Funge program to measure elapsed time much more finely than the clock values returned by y.

After successfully loading HRTI, the instructions E, G, M, S, and T take on new semantics.

Instruction Args Description
G ( — tick) ‘Granularity’ pushes the smallest clock tick the underlying system can reliably handle, measured in microseconds.
M ( — ) ‘Mark’ designates the timer as having been read by the IP with this ID at this instance in time.
T ( — dt) ‘Timer’ pushes the number of microseconds elapsed since the last time an IP with this ID marked the timer. If there is no previous mark, acts like r.
E ( — ) ‘Erase mark’ erases the last timer mark by this IP (such that T above will act like r)
S ( — μs) ‘Second’ pushes the number of microseconds elapsed since the last whole second.

The timer and mark-list are considered global and static, shared amongst all IP's, in order to retain tame behaviour.

This timer is not affected by 'time travel' contrivances.

Addendum: In rfunge, the mark is not global, but specific to an IP – but it is inherited by child IPs. The definition is ambiguous as to what E does: we interpret it as erasing the mark, such that T then acts like r (meaning there is no ‘mark-list’), i.e. MME is equivalent to zzz, not to Mzz.

"JSTR" 0x4a535452

One of Jesse van Herk’s fingerprints

Instruction Args Description
P (Vd Va n — ) pop n cells off of the stack and write at Va with delta Vd.
G (Vd Va n — 0gnirts) read n cells from position Va and delta Vd, push on stack as a string.

This extension is the Right Way to handle string writing/reading in fungespace. multidimensionality, people!

Addendum: P pops the cells off the stack after it has popped its vector arguments. These instructions respect the storage offset.

The rcFunge 2 manual has the instructions the wrong way around, but rcFunge 2 still implements them correctly.

"LONG" 0x4c4f4e47 ‘Long integers’

From the rcFunge docs

Instruction Args Description
A (ah al bh bl — rh rl) Addition
B (ah al — rh rl) Absolute value
D (ah al bh bl — rh rl) Division
E (n — rh rl) Sign extend single to long
L (ah al n — rh rl) Shift left n times
M (ah al bh bl — rh rl) Multiplication
N (ah al — rh rl) Negate
O (ah al bh bl — rh rl) Modulo
P (ah al — ) Print
R (ah al n — rh rl) Shift right n times
S (ah al bh bl — rh rl) Subraction
Z (0gnirts — rh rl) Ascii to long
  • long integers are 2 cell integers, if the interpreter's cell size is 32, then long integers are 64-bits.
  • Division by zero results in zero, not error

Addendum: rfunge implements 128-bit integers in 64-bit mode; it may be the only interpreter to do so.

"MODU" 0x4d4f4455

From the catseye library (‘Under development.’)

The MODU fingerprint implements some of the finer, less-well-agreed-upon points of modulo arithmetic. With positive arguments, these instructions work exactly the same as % does. However, when negative values are involved, they all work differently:

Instruction Args Description
M (a b — r) signed-result modulo
U (a b — r) Sam Holden's unsigned-result modulo
R (a b — r) C-language integer remainder

Addendum: This fingerprint is poorly defined and, for the most part, equally poorly implemented. Of all the implementations I’ve seen, other than rfunge, only CCBI gets it right.

It’s easiest to define what these commands need to do by thinking about the remainder in integer division. There are different ways to defining integer division, but for all of them we get a result

n ÷ d = q rem r

which we can rearrange as

q × d + r = n

If the result of the modulo operator is supposed to be some kind of integer division remainder, then there must be a sound definition of integer division for which the above holds!. C uses truncating division (rounding q to 0) and the appropriate remainder, which is fine and all implementations get right. This is of course a ‘signed-result modulo’, but as the instructions are supposed to do different things and the result for positive arguments is supposed to be unchanged, we end up with floor division (rounding q to -∞), which most implementations also get right.

U, the unsigned-result modulo, however, is frequently implemented as the absolute value of C modulo result, and I do not believe there is any coherent definition of integer division for which this is correct. We can instead define our division to round q in whatever direction makes r positive (sometimes called ‘Euclidean division’). This is what CCBI and rfunge do.

(We could also approach the problem from the point of view of modulo arithmetic, but then we’d run into invariants broken even by the C-language remainder)

"NULL" 0x4e554c4c

From the catseye library

After successfully loading fingerprint 0x4e554c4c, all 26 instructions A to Z take on the semantics of r.

This can be loaded before loading a regular transparent fingerprint to make it act opaquely.

"REFC" 0x52454643 ‘Referenced Cells Extension’

From the catseye library (‘Under development.’)

The REFC fingerprint allows vectors to be encoded into and decoded from single scalar cell values.

After successfully loading REFC, the instructions D and R take on new semantics.

Instruction Args Description
R (Va — ref) ‘Reference’ pops a vector off the stack, and pushes a scalar value back onto the stack, unique within an internal list of references, which refers to that vector.
D (ref — Va) ‘Dereference’ pops a scalar value off the stack, and pushes the vector back onto the stack which corresponds to that unique reference value.

The internal list of references is considered shared among all IP's, so a global static can be used to store this list, so that this extension remains tame.

Addendum: In rfunge, the reference list is not global, but specific to an IP – but it is inherited by and shared with/between child IPs. The behaviour is the same as long as the fingerprint is loaded and first used before any child IPs are spawned.

"ROMA" 0x524f4d41 ‘Funge-98 Roman Numerals’

From the catseye library (‘Under development.’)

After successfully loading ROMA, the instructions C, D, I, L, M, V, and X take on new semantics.

Instruction Args Description
C ( — n) pushes 100 onto the stack.
D ( — n) pushes 500 onto the stack.
I ( — n) pushes 1 onto the stack.
L ( — n) pushes 50 onto the stack.
M ( — n) pushes 1000 onto the stack.
V ( — n) pushes 5 onto the stack.
X ( — n) pushes 10 onto the stack.

Note that these are just digits, you still have to do the arithmetic yourself. Executing MCMLXXXIV will not leave 1984 on the stack. But executing MCM\-+LXXX+++IV\-++ should.

"SOCK" 0x534F434B ‘tcp/ip socket extension’

From the rcFunge docs

Instruction Args Description
A (s — prt addr s) Accept a connection
B (s ct prt addr — ) Bind a socket
C (s ct prt addr — ) Open a connection
I (0gnirts — addr) Convert an ascii ip address to a 32 bit address
K (s — ) Kill a connection
L (n s — ) Set a socket to listening mode (n=backlog size)
O (n o s — ) Set socket option
R (V l s — bytes) Receive from a socket,
S (pf typ pro — s) Create a socket
W (V l s — retcode) Write to a socket

note: All functions act as r on failure

  • addr: 32 bit destination address
  • ct:
    • 1=AF_UNIX
    • 2=AF_INET
  • o:
    • 1=SO_DEBUG
    • 2=SO_REUSEADDR
    • 3=SO_KEEPALIVE
    • 4=SO_DONTROUTE
    • 5=SO_BROADCAST
    • 6=OOBINLINE
  • pf:
    • 1=PF_UNIX
    • 2=PF_INET
  • prt: Port to connect to
  • s: Socket identifier
  • typ:
    • 1=SOCK_DGRAM
    • 2=SOCK_STREAM
  • pro:
    • 1=tcp
    • 2=udp
  • V: Vector to io buffer

Clarification

The socket descriptor s used in these functions could be either an index into a table of open sockets or else use the id returned by the OS. In either case the socket identifier needs to be usable by other IPs, therefore a socket table that is global to all IPs or else use the OS descriptors.

ct=1 and pf=1 are a broken spec and should not be implemented. Usage of either of these should reflect.

Addendum: rfunge does not support SO_DEBUG, SO_DONTROUTE, or OOBINLINE. (Or UNIX sockets of course). This fingerprint is not available on the web or in sandbox mode.

"TURT" 0x54555254 ‘Simple Turtle Graphics Library’

From the catseye library (‘Under development.’)

Instruction Args Description
L (angle — ) Turn Left
R (angle — ) Turn Right
H (angle — ) Set Heading (0 = east)
F (dist — ) Go Forward
B (dist — ) Go Back
P (pos — ) Set Pen Position (0 = up, 1 = down)
C (colour — ) Set Pen Colour
N (colour — ) Clear with Colour
D (disp — ) Show Display (0 = off, 1 = on)
T (x y — ) Teleport
E ( — pos) Query Pen Position
A ( — angle) Query heading
Q ( — x y) Query position
U ( — x1 y1 x2 y2) Query Bounds
I ( — ) Print current Drawing (if possible)

All angles are in degrees, all distances are in pixels.

To keep this fingerprint tame, a single Turtle and display is defined to be shared amongst all IP's. The turtle is not defined to wrap if it goes out of bounds (after all this interface might just as well be used to drive a real turtle robot.)

Addendum: RFunge supports this fingerprint both on the web and on the desktop; on the web, the ‘display’ is a <canvas> embedded in the user interface and I triggers a PNG download. The native version opens a GUI window (if possible) when the TURT display is requested, and writes an SVG file to the current directory on I. This corresponds to the behaviour of CCBI and cfunge, which do not support direct GUI output. TURT is disabled in sandbox mode. RFunge can be compiled without GUI support.