
16-bit math look-up tables – the unexpected power of scaled-integer math - mirceasoaica
http://wilsonminesco.com/16bitMathTables/
======
raymondh
For those who are interested, CORDIC (for COordinate Rotation DIgital
Computer) is another technique from that era. It "is a simple and efficient
algorithm to calculate hyperbolic and trigonometric functions, typically
converging with one digit (or bit) per iteration." See
[https://en.wikibooks.org/wiki/Digital_Circuits/CORDIC](https://en.wikibooks.org/wiki/Digital_Circuits/CORDIC)

For instructional purposes, here is a simple Python implementation that uses
only adds and shifts in the inner loop, followed by a single scaled-multiply
to finish it up: [https://code.activestate.com/recipes/576792-polar-to-
rectang...](https://code.activestate.com/recipes/576792-polar-to-rectangular-
conversions-using-cordic)

~~~
bsder
IIRC, CORDIC has some issues as you scale the number of bits you want--you
can't just run CORDIC 64 times for 64-bits of accuracy, for example.

I think the point of diminishing returns is 14-16 bits, but it's been a long
time and I'd be happy to be proven wrong.

------
weinzierl
Back in the day of 80286's and 80386's there was a popular Fractal generating
software that did all calculations in fixed point arithmetic because PCs
usually had no FPU back then.

Fractint[1], the site has a certificate error, but otherwise works fine, even
the software still gets updated from time to time.

[1] [https://fractint.org/](https://fractint.org/)

~~~
quakeguy
Used it to generate uniform random plasma fields for game textures. Great
program!

~~~
weinzierl
With the right color map they made a nice sky with clouds. Color cycling them
through a smooth full color map was also nice.

------
Animats
Cute. However, unless you're using a CPU from the 6502 era, it's probably not
worth the trouble for multiplication and division. Today's low-end CPUs have
good multiply hardware, and for a few dollars more, you get a decent FPU. Trig
functions, though, may be worth precomputing. The standard libraries for trig
functions often grind their way out to far more precision than you need for
graphics or control, and that takes time. Interpolating from a modest sized
table can be faster.

~~~
weinzierl
> However, unless you're using a CPU from the 6502 era, it's probably not
> worth the trouble for multiplication and division.

When we talk PC, fixed point math was popular a few generations longer than
the 6502 era. The 6502 had no multiply and division instructions at all, and
up to the 80386 there was only integer multiply and division and that was slow
as molasses. Before the 80486 fixed point wasn't a matter of speed, it was a
matter of survival (at least for graphics and such).

~~~
louthy
indeed, I was using fixed point maths on PlayStation 1 games in the mid to
late 90s. It was often responsible for the gaps you'd see between polygons on
many PS1 games.

~~~
rasz
Gaps were mostly a sign of sloppy developers and rushed schedules. Compare
Tomb Raider 1 on both PC/PSX with Destruction Derby (reflections) and Gran
Turismo 1/2 (polyphony).

~~~
louthy
Yes, there were ways to avoid it (shared vertex calculations), but the effect
seen was mostly where there are two separate vertices that are supposed to be
at the same position, aren't, because each vertex was positioned with
different transformation matrices.

------
kosma
I used this exact approach just yesterday when I needed to calculate some sine
values on an 8-bit MCU. Turns out including a precalculated table takes way
less program memory than linking softfloat and trig libraries. 8051 is not
dead, folks!

------
shpx
Related to 16 bit lookup tables, unum is a format for representing numbers as
sets of number ranges as an alternative to floats.

[http://www.johngustafson.net/presentations/Unums2.0.pptx](http://www.johngustafson.net/presentations/Unums2.0.pptx)

[http://www.johngustafson.net/presentations/Unums2.0.pdf](http://www.johngustafson.net/presentations/Unums2.0.pdf)

[https://arxiv.org/pdf/1701.00722.pdf](https://arxiv.org/pdf/1701.00722.pdf)

[https://en.wikipedia.org/wiki/Interval_arithmetic](https://en.wikipedia.org/wiki/Interval_arithmetic)

~~~
Mindless2112
Unums are unlikely to gain much usage. Posits[1][2], also by Gustafson, are a
more reasonable alternative to IEEE-754 floating point (but will still have a
difficult time displacing IEEE-754, if they can at all).

[1]
[http://web.stanford.edu/class/ee380/Abstracts/170201-slides....](http://web.stanford.edu/class/ee380/Abstracts/170201-slides.pdf)
[2]
[https://www.youtube.com/watch?v=aP0Y1uAA-2Y](https://www.youtube.com/watch?v=aP0Y1uAA-2Y)

~~~
adrianratnapala
Posits seem impressive. My only concern is the lack of NaNs seems like a bug
rather than a feature.

It's true that some programmers do the silliest things when faced with NaNs.
But the fact is they are useful. You often want to do calculations over big
matrices, where some elements simply don't have a mathematically defined
answer (usually because of div0s but also because input data might have
holes).

It would be a royal pain if the whole calculation stopped every time you had
to add two infinities.

~~~
dnautics
>is the lack of NaNs seems like a bug rather than a feature.

I think this is a reasonable concern. I'll propose to John that we make there
be an optional "mode" where the infinity token is treated as "NaN". In
reality, this mode just amounts to "ignore NaN traps", because the way that
it's done in my hardware models, it requires almost no extra hardware.

~~~
jacobolus
What if we want both NaN and infinity?

~~~
dnautics
if you really want both, then either 1) use IEEE floats or 2) write your own
data type, or 3) used a boxed data type, which is really the best solution for
the dominant "missing data" abuse case anyways.

------
emersonrsantos
Āryabhaṭa's sine table, the first known mathematical LUT, was made around 500
DC:

[https://en.wikipedia.org/wiki/Āryabhaṭa's_sine_table](https://en.wikipedia.org/wiki/Āryabhaṭa's_sine_table)

~~~
jacobolus
> _first known mathematical LUT_

Babylonian multiplication and reciprocal tables are about 2500 years older.

For that matter, Hipparchus and Ptolemy’s chord tables are also centuries
older,
[https://en.wikipedia.org/wiki/Ptolemy's_table_of_chords](https://en.wikipedia.org/wiki/Ptolemy's_table_of_chords)

------
rasz
>And by the way, real-world I/O in control situations is never floating-point,
whether timers, counters, A/D and D/A converters, servos, etc..

well, actually ;) Adlib/Sound Blaster Yamaha OPL2 and OPL3 both used external
Floating Point DACs (YM3014B,YAC512)

------
marktangotango
>> Jack Crenshaw addresses it in chapter 5 of his fine book "Math Toolkit for
Real-Time Programming."

Ah shit, can't believe I missed this, all these years. Jack Crenshaw ie Let's
Build a Compiler. Love that guy.

------
otempomores
Is there a stdclib which allows for easy replacement of expensive funtions
like fsin or fcos with lutables? Also do those not poison the cache?

