💾 Archived View for thrig.me › blog › 2023 › 11 › 04 › old-floats.gmi captured on 2024-07-09 at 01:13:02. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-11-14)

-=-=-=-=-=-=-

Old Floats

Floating point support is taken for granted in these days of abundance. In the olden times one might instead have to make do with scaled integers, or a (buggy?) co-processor that did the floating point on the side. Obscure languages still implement floating point support with a separate stack, such as retroforth. In this language, floating point values need a "." prefix to tell them apart from other words, and the "f:" prefix is used for operations on the floating point stack. The leading sigils make for an easier parse: dot?—shunt it off to the "parse a floating point value" code.

    $ retro
    RETRO 12 (2024.4)
    524288 Max, 45027 Used, 479261 Free
    .3.14 .2 f:* f:put nl
    6.280000

The stack can be indicated by using subtraction following a swap. dc(1) is similar, though the "r" to reverse (swap) the top of the stack may not be portable.

    .5 .2 f:swap f:- f:put nl
    -3.000000
    bye
    $ dc
    5 2 - p
    3
    5 2 r - p
    -3
    q

There may still be a floating point stack in a CPU near you. This can be a source of hilarious bugs if the hardware stack gets out of sync with the software. Usually these are bugs in the compiler (or sometimes the hardware) and thankfully are pretty rare. Something you usually only hear stories about.

So assuming you have an i386 or AMD64 CPU (real or emulated) and GCC (or a compatible compiler) one can poke at the FPU directly. This is the same swap and subtract as shown above.

    #include <stdio.h>
    
    int
    main(void)
    {
        float x = 2.0;
        float y = 5.0;
        asm("fld %1\n\t"
            "fld %2\n\t"
            "fxch\n\t"       // swap
            "fsubp\n\t"      // subtract and pop
            "fstp %0\n"      // halt FPU and store result
            : "=m"(x)        // output (%0)
            : "m"(x), "m"(y) // input  (%1, %2)
        );
        fprintf(stderr, "%.4f\n", x);
    }

float-sqrt.c

On OpenBSD gcc may be called egcc if you installed it from ports.

    $ egcc float-sqrt.c
    $ ./a.out
    -3.0000

Higher level languages hide this stuff, unless the abstraction leaks. They also may use modern floating point instructions rather than old things from the 8087 days. Something to play around with might be to leave the floating point stack in an invalid state and then see what happens. Do you get any weird error messages?

Scaled Integers

Scaled integers avoid the need to use floating point math libraries or hardware. This has advantages and disadvantages. A good treatment can be found in the book "Starting Forth" in the "No Weighting" section that computes the weight of a cone-shaped pile of material using only fixed-point arithmetic.

Why learn old and low-level things like this? Not many will need to know it, but if too few people know it, then see "The Machine Stops" (E. M. Forster).

tags #asm #forth #rpn

https://git.sr.ht/~crc_/retroforth

http://man.openbsd.org/man1/dc.1

P.S. some folks make their documentation hard to get. Probably they do not like browsers that do not do cookies and javascript and whatnot.

You don't have permission to access "http://www.intel.com/content/dam/develop/external/us/en/documents/introduction-to-x64-assembly-181178.pdf" on this server.