The Machines · Core numerics

math

Derived Maths — machines/math.shoddy

the math machine's icon

Summary

math is the comfortable middle layer of Shoddy's number work. The runtime — the engine that runs your program — already hands you the hard primitives, the words that need real numerical precision baked in: Sin, Cos, Sqr (square root), Exp, Log, Pi, and the arithmetic and rounding words. This machine does not reimplement any of those. It sits on top of them and adds the everyday conveniences you would otherwise write out by hand every time: the constant E, a whole Tau instead of two Pis, degrees-to-radians (radians are the angle unit the trig words use — a full circle is 2×Pi, not 360), clamping and interpolation (pinning a value inside bounds, and sliding smoothly between two values), a distance formula, base-2 logs. Each one is a nice, small, obvious thing — a line or two over a builtin, a word the engine itself supplies, that you already had. It includes nothing else, so a program can pull in math on its own.

A Brief History of the Logarithm

The most useful trick in this machine's territory was worked out by two men. One of them was born a few miles from the mills this language is named for. John Napier published the logarithm in 1614: a table that turned multiplication, the slow operation, into addition, the fast one. Henry Briggs — born at Warley Wood in the parish of Halifax, in the West Riding — read it and travelled to Edinburgh to meet Napier. Briggs talked him into the one improvement that made the idea universal: put the tables on base 10, so the whole-number part of a logarithm is just how many digits the number has. Briggs then computed tens of thousands of the entries himself, by hand, to fourteen places. For the next three and a half centuries, science and engineering ran on his tables and their pocket form, the slide rule. The runtime hands Shoddy Log. This machine adds Log2 and LogBase in Briggs's spirit: the base you compute in and the base you think in need not be the same one.

Why It's Useful

Real programs are forever needing the same little scraps of arithmetic. You want to keep a value inside sensible bounds (Clamp). You want to slide smoothly from one number to another — a fade, a camera move, a progress bar (Lerp). You have an angle in degrees but the trig builtins speak radians (Rad). You want the distance between two points (Dist), or a random number in a range, or a log in some base that isn't 10 or e. None of these is hard. But writing them out inline every time is tedious and easy to fumble — is it lo + (hi - lo) * t or the other way round? math gives each a plain name you can trust, so the arithmetic reads like what it means. Reach for it any time you're doing more than plus and minus: graphics, animation, geometry, simulation, or just tidying a raw number into a rounded, bounded one.

User's Guide

Everything here is a plain function over numbers. Pass numbers in, get a number back — or, for Chance, a Boolean, a true-or-false value. There is nothing to open or set up. Include the file and call the words. The one wrinkle to know is a rule the machine sets for itself: no word here may share a name with a builtin. In Shoddy a Def (a word you define yourself) silently outranks a builtin of the same name. Redefining, say, Log would therefore quietly hijack it everywhere — a nasty surprise. That is why the natural log stays the Log builtin and the base-10 log stays Log10. This file adds only the ones the runtime doesn't already provide: Log2 and LogBase.

Include "math.shoddy"

Def Main()
    Print(Tau())                    ' 6.283... — a full turn, in radians
    Print(Rad(180))                 ' 3.14159... — 180 degrees as radians

    Print(Clamp(42, 0, 10))         ' 10  — pinned to the top of the range
    Print(Lerp(0, 100, 0.25))       ' 25  — a quarter of the way from 0 to 100
    Print(RoundTo(3.14159, 2))      ' 3.14

    Print(Dist(0, 0, 3, 4))         ' 5   — Pythagoras, done for you
    Print(Log2(8))                  ' 3

    If Chance(0.5) Then             ' heads-or-tails, true half the time
        Print("heads")
    Else
        Print("tails")

A few things worth remembering:

Builtins

The thirty numeric words the runtime dispatches — not defined here, documented here

These are not math's Defs. The engine dispatches them, and a Def whose name is a builtin is refused. They are listed on this page because math is the machine whose domain they belong to. Its own header has always named all thirty as what it is built on, and this is that claim made word by word. They need no Include. The same thirty are documented in machines/math.shoddy's own header block.

Number is the only numeric type — a double, the standard format computers use for decimal numbers. There is no integer type, so "whole number" below means a double with no fractional part, exact to 253. Angles are radians at every boundary; Rad and Deg below convert. All thirty are pure — the same inputs always give the same answer — except Seed.

Rnd is not here, though this machine calls it. RandRange, RandInt, Pick and Chance are all Rnd underneath. But a builtin is documented in one machine only, and Rnd's machine is random, whose whole header is a claim on it. Seed is here, and the split is deliberate: random is seedless by construction, and says so in as many words. The word that reseeds the generator would contradict the machine it otherwise sits beside. It reseeds random's words just the same.

Arithmetic

WordDescription
a + b, a - b, a * b, a / bThe four operators. + also joins two Strings, which is why the reckoner's dictionary needs no separate word for &.
a Mod bThe remainder. It takes its sign from a — the truncated form, the same rule BASIC and C use. Wrap is the one that does not.
Wrap(a, b)Floored modulo: the answer takes its sign from b, so Wrap(-1, 360) is 359 where -1 Mod 360 is −1. This is the one for angles, ring buffers and anything that comes round again.
a ^ ba raised to the power b. It binds tighter than any other operator.
Negate(x)The number with its sign turned round.
Abs(x)Its magnitude, sign discarded.
Sgn(x)−1, 0 or 1, according to the sign.
Min(a, b) / Max(a, b)The smaller and the larger. Clamp below is both at once, and is usually what a bounded value wants.
Sqr(x)The square root. Named for BASIC's SQR and not for squaring — squaring is x ^ 2.

Rounding — and there are four

The difference matters and is easy to get wrong. Floor and Ceil each go one way, regardless of sign. Fix goes towards zero, so it and Floor differ on every negative number. Round goes to the nearest.

WordDescription
Floor(x)Down, towards minus infinity. Floor(-2.5) is −3.
Ceil(x)Up, towards plus infinity. Ceil(-2.5) is −2.
Round(x)To the nearest whole number. RoundTo below rounds to a given number of places, and str's ToFixed formats.
Fix(x)Towards zero — the fractional part simply dropped. Fix(-2.5) is −2, where Floor(-2.5) is −3.

Exponential and logarithmic

WordDescription
Exp(x)e raised to the power x.
Log(x)The natural logarithm, base e. The name is BASIC's, and it is the one people misread: base ten is Log10.
Log10(x)The base-ten logarithm. Log2 and LogBase below are derived from these two, since the runtime supplies no other base.

Trigonometry, in radians

WordDescription
Sin(x) / Cos(x) / Tan(x)The three, taking radians. Rad below converts from degrees.
Atn(x)The arctangent, in radians. Atn2 is the one that knows which quadrant the point is in.
Atn2(y, x)The angle of the point (x, y), in radians, in the right quadrant. Note the argument order: y first, as in C's atan2.
Asin(x) / Acos(x)The inverse sine and cosine, in radians. Outside −1 … 1 there is no real answer.
Tanh(x)The hyperbolic tangent. It saturates towards 1 and −1, so it never overflows. That is why neural uses it as its activation function. The other eleven hyperbolics are eng's.
Pi()The constant. Tau below is two of them, and E is this file's rather than the runtime's.

The one impure word

WordDescription
Seed(n)Reseeds the engine's random generator, so that Rnd answers reproducibly from here on. That covers everything built on it: random's Random, RandomRange, RandomInt, Shuffle and Sample, and this machine's own RandRange, RandInt, Pick and Chance. It is the only builtin on this page with an effect, and the reason the game-flavoured randomness below is not pure.

Word Reference

Every word — all pure functions over numbers

Constants

WordDescription
E()Euler's number, about 2.71828 — computed as Exp(1). The base of the natural log.
Tau()A full turn in radians, about 6.28318 — 2 × Pi. Often the friendlier circle constant when you're thinking in whole turns.

Angles builtins speak radians

WordDescription
Rad(deg)Converts an angle in degrees to radians, ready for the trig builtins.
Deg(rad)Converts an angle in radians back to degrees, for display or turtle-style headings.
Angle(dx, dy)The direction of a vector (dx, dy) as a radian angle in the range (-Pi, Pi]. Argument order reads naturally, left to right.

Parts and rounding

WordDescription
Frac(x)The fractional part of x — what's left after truncating toward zero. So Frac(-3.25) is -0.25.
RoundTo(x, n)Rounds x to n decimal places.

Shaping a range

WordDescription
Clamp(x, lo, hi)Pins x into the range lo..hi: below lo becomes lo, above hi becomes hi.
Lerp(a, b, t)Linear interpolation: the point a fraction t of the way from a to b. t = 0 gives a, t = 1 gives b.
InvLerp(a, b, x)The inverse of Lerp: what fraction of the way from a to b the value x sits at.
Remap(x, inLo, inHi, outLo, outHi)Moves x linearly from the input range onto the output range — InvLerp then Lerp, in one step.
Smoothstep(edge0, edge1, x)Smooth (Hermite) interpolation from edge0 to edge1, clamped to [0, 1] at the edges — an eased ramp instead of a straight one.

Geometry

WordDescription
Hypot(x, y)The length of the hypotenuse — Sqr(x² + y²) — i.e. the distance from the origin to the point (x, y).
Dist(x0, y0, x1, y1)The straight-line distance between two points.

Logarithms natural and base-10 are builtins

WordDescription
Log2(x)The base-2 logarithm of x.
LogBase(base, x)The logarithm of x in any base you name.

Random on the Rnd builtin; Seed reproduces

WordDescription
RandRange(lo, hi)A random floating-point number in [lo, hi)lo possible, hi never quite.
RandInt(lo, hi)A random whole number in [lo, hi], both ends included.
Pick(xs)A uniformly-chosen element of a non-empty list or array.
Chance(p)True with probability p: p ≤ 0 never, p ≥ 1 always. A weighted coin.

Who Uses It

UserHow
demographicsRoundTo trims the reports to printable precision.
devils-dustThe steering arithmetic — Clamp, Lerp, Smoothstep, Hypot, Dist — and the dice: RandRange, Pick, Chance.
engRad, Deg, Angle, Hypot, LogBase and the whole interpolation family, re-exported under Eng names.
ephemerisRad, Deg, Clamp and Hypot, exactly as geo uses them.
finRoundTo under FinRound.
geoRad and Deg at the degrees boundary, Clamp guarding every Asin and Sqr against a rounding error past ±1, Hypot, and RoundTo for the seconds of an angle.
invadersClamp, Dist and RandInt in the core.
irisRoundTo trims the reports to printable precision.
oregonPick rolls the trail's misfortunes.
pac-vt100RandInt and Pick are the ghosts' dice.
turtleRad, Deg and Dist — headings in degrees, geometry in radians.
weather-glassRad and Deg for the NOAA solar algorithm that computes sunrise and sunset rather than fetching them.

The Machines It Uses

None. It is built on the numeric builtins alone, which is what lets every other machine and mill lean on it without ceremony.