Skip to content

Math

Math provides random-number generation, integer and floating-point arithmetic helpers, transcendental functions, and a full set of mathematical constants. All methods are static.

#import <Math.xt>

The class makes heavy use of xtc’s overloading by return type for zero-argument methods — Math.rand() and the constants like Math.PI() resolve based on the variable being assigned to. The compiler emits the version that produces the requested type.

xtc’s RNG is a small linear-feedback generator. By default it auto-seeds from the Atari hardware (RANDOM register at $D20A) at first use; you can also seed it explicitly.

static void setSeed(u16 seed); // re-seed the generator
static void step(void); // advance the generator one tick
static u8 rand(void);
static u16 rand(void);
static u32 rand(void);
static float rand(void); // 0.0 ≤ x < 1.0
static double rand(void); // 0.0 ≤ x < 1.0
u8 b = Math.rand(); // 0..255
u16 w = Math.rand(); // 0..65535
u32 l = Math.rand(); // 0..2^32-1
float f = Math.rand(); // 0.0 ≤ f < 1.0
double d = Math.rand(); // 0.0 ≤ d < 1.0
static u8 rand(u8 max); // 0 ≤ x < max
static u8 rand(u8 lo, u8 hi); // lo ≤ x ≤ hi
static u16 rand(u16 max); // 0 ≤ x < max
static u16 rand(u16 lo, u16 hi); // lo ≤ x ≤ hi
u8 d6 = Math.rand((u8)1, (u8)6); // dice roll
u16 cell = Math.rand((u16)40); // 0..39
static i8 abs(i8 v);
static i16 abs(i16 v);
static i32 abs(i32 v);
static float abs(float v);
static double abs(double v);
i32 delta = Math.abs(target - current);
static float sqrt(float v);
static double sqrt(double v);
float hypot = Math.sqrt(dx * dx + dy * dy);
static float ln(float v);
static double ln(double v);
static float exp(float x);
static double exp(double x);

ln is natural log (base e); exp is e^x. For other bases, multiply / divide by Math.LN2(), Math.LN10(), etc.

pow is overloaded by exponent type — for integer exponents the integer-typed overload is much cheaper than the float-by-float version.

static float pow(float base, float power);
static float pow(float base, i16 power);
static double pow(double base, double power);
static double pow(double base, i16 power);
static double pow(double base, i32 power);
static double pow(double base, u32 power);
float r2 = Math.pow(r, (i16)2); // squared, integer fast path
float v = Math.pow((float)2.0, (float)0.5); // square root via pow

Angles are in radians. All four functions exist in both float and double precision.

static float sin(float angle);
static float cos(float angle);
static float tan(float angle);
static float atan(float x);
static double sin(double angle);
static double cos(double angle);
static double tan(double angle);
static double atan(double x);
float a = Math.PI() / 4;
float s = Math.sin(a); // ≈ 0.7071
float c = Math.cos(a);

Both float and double versions of the standard constants are available; the compiler picks based on the assignment target.

MethodValue
Math.E()Euler’s number
Math.LOG2E()log₂(e)
Math.LOG10E()log₁₀(e)
Math.LN2()ln(2)
Math.LN10()ln(10)
Math.PI()π
Math.PI_2()π / 2
Math.PI_4()π / 4
Math.INV_PI()1 / π
Math.TWO_PI()
Math.TWO_SQRTPI()2 / √π
Math.SQRT2()√2
Math.SQRT1_2()√(1/2)
float pi_f = Math.PI(); // float overload
double pi_d = Math.PI(); // double overload

float in xtc is a 5-byte binary value: 1 sign byte + 1 signed binary exponent byte + 3 bytes of mantissa (24 bits) with an implicit leading 1. The value is (1 + mantissa / 2^24) * 2^exp for normal numbers. double is 8 bytes — same shape, with a 48-bit mantissa for ~15 digits of precision.

This is not the Atari OS math pack format. The Atari ROM uses BCD-encoded floats with a 6-decimal-digit mantissa; xtc uses pure binary, which is much faster to multiply and divide on a CPU that has no decimal arithmetic support, at the cost of needing a binary↔ASCII conversion routine to print. The format is defined by the xtc runtime, not by the host OS, so it’s identical on Atari and on Commodore — only the helper-routine implementations differ per platform.

The hand-written assembler routines in support/generic/asm/float/ and support/generic/asm/double/ implement add, subtract, multiply, divide, and the math functions on this format. Code generated by xtc emits JSR to those routines automatically when float operations appear in source.

Math.xt uses conditional compilation extensively — every transcendental, the entire double family, the pow overloads, and the constants are gated behind feature flags (ENABLE_DOUBLE, ENABLE_TRIG, etc.) so a program that only needs rand() doesn’t pay the binary cost of sin and cos. The defaults pull in everything; pass -DENABLE_DOUBLE=0, -DENABLE_TRIG=0, etc. to opt out per feature.

The Math class also exists under support/commodore/lib/Math.xt for the C64. The API is the same — same overloads, same constants — and because the xtc float and double formats are platform-independent (binary, defined by the language not the host OS), the bit-level layout of values is identical on both platforms. The C64 implementation differs only in its assembly helpers and per-platform tuning.