GizStack
View .mdOpen in ChatGPTOpen in Claude

gizdb:decimal

Exact decimals, as PostgreSQL's NUMERIC: a value is C × 10^-s with a scale s of 0..16383 and at most 131072 digits before the point. A coefficient that fits an i64 (most values) is the narrow case: c and s, so columns and SIMD kernels work on c alone and a Dec stays 24 bytes (a wider Value made the decimal and integer sums 10-14% slower). A wider coefficient is the wide case: m[0] = s << 1 | sign, then |C| in base-10^9 limbs with the least significant first and no zero limb on top. Read a Dec through decScale, decCoef, decNegative and the limb helpers here. A value has one form at a scale, so === compares values of one scale. Every operation is exact, or rounds half away from zero at a scale it names, or reports overflow (none): nothing goes through binary floating point. ln, log, exp and power are correctly rounded at the scales PostgreSQL picks. Oracle's NUMBER keeps 40 digits by its own rule (numberArith, decNumber).

gizlang
import * as Decimal from "gizdb:decimal";

Types

Dec

gizlang
type Dec = | { kind: "narrow"; c: i64; s: i32; } | { kind: "wide"; m: Vec<u64>; }

An exact decimal: a 64-bit coefficient with its scale, or a wide sign-magnitude form for larger values.

  • narrow
  • wide

DecRead

gizlang
type DecRead = | { kind: "ok"; value: Dec; } | { kind: "invalid"; } | { kind: "overflow"; }

What a text spells as a decimal: a value, not a number, or a number past the limits.

  • ok
  • invalid
  • overflow

Parts

gizlang
type Parts = { wh: i64; wl: u64; f1: u64; f2: u64; sticky: bool; more: Vec<u64>; }

A finite number split as floor(v), 128-bit two's complement (wh its high word, wl its low bits), and its fraction in 10^-38 units (f1 the first 19 digits, f2 the next 19), with sticky when digits remain below those: what orders and compares integers, floats and decimals exactly together. A decimal's digits past those are more, 19 a word with no zero word last (a float's are not kept: it orders before a decimal of the same first 38 fraction digits). A floor from 2^127 on passes every float the parts compare with: it saturates.

  • wh: i64
  • wl: u64
  • f1: u64
  • f2: u64
  • sticky: bool
  • more: Vec<u64>

Functions

pow10

gizlang
function pow10(n: i64): i64

10^n for 0 <= n <= 18.

Effects: fail.

decOf

gizlang
function decOf(c: i64, s: i64): Dec

A coefficient that fits an i64 at scale s.

decOfInt

gizlang
function decOfInt(x: i64): Dec

The decimal of the integer X.

narrow

gizlang
function narrow(d: Dec): bool

Whether the coefficient is c alone.

decNegative

gizlang
function decNegative(d: Dec): bool

Whether D is below zero.

Effects: fail.

decZero

gizlang
function decZero(d: Dec): bool

Whether D is zero.

decScale

gizlang
function decScale(d: Dec): i64

The scale.

Effects: fail.

decCoef

gizlang
function decCoef(d: Dec): i64

The coefficient of a narrow value; the sign (1 or -1) of a wide one.

Effects: fail.

decShift

gizlang
function decShift(d: Dec, s: i64): Dec

The same coefficient at scale s: d × 10^(scale - s).

Effects: fail.

decWithin

gizlang
function decWithin(d: Dec): bool

Whether a value is within NUMERIC's limits: scale 16383 and 131072 digits before the point.

Effects: fail.

precisionOf

gizlang
function precisionOf(d: Dec): i64

Significant digits of the coefficient: what DECIMAL(p, s) checks against p.

Effects: fail.

decWords

gizlang
function decWords(d: Dec): Vec<i64>

The coefficient as 64-bit two's complement words, the least significant first: one word when it fits an i64.

Effects: fail.

decOfWords

gizlang
function decOfWords(w: Vec<i64>, s: i64): Dec

The value of two's complement words (decWords) at scale s.

Effects: fail.

readDecimal

gizlang
function readDecimal(text: string): DecRead

The decimal a text spells, as PostgreSQL's numeric_in: [+-]digits[.digits][e[+-]digits], surrounding spaces allowed. Every digit stays; the scale is the digits after the point less the exponent, at least 0.

Effects: fail.

parseDecimal

gizlang
function parseDecimal(text: string): Option<Dec>

readDecimal's value, or none for a text that is not a number or a number past the limits.

Effects: fail.

decOfFloat

gizlang
function decOfFloat(f: f64, scale: i64): Option<Dec>

The decimal of a float at its shortest exact digits, then rounded to scale (-1: as many as those digits have); none for NaN, infinities and what does not fit.

Effects: fail.

decText

gizlang
function decText(d: Dec): string

The decimal as text at its scale: -12.340, 0.05, 7.

Effects: fail.

trimmed

gizlang
function trimmed(d: Dec): Dec

The same value without trailing fractional zeros (2.50 → 2.5, 3.00 → 3).

Effects: fail.

decFloat

gizlang
function decFloat(d: Dec): f64

The nearest f64 (correctly rounded, through the digits); ±infinity past the f64 range.

Effects: fail.

rescale

gizlang
function rescale(d: Dec, s: i64): Option<Dec>

The value at scale s (0..16383): more digits are exact, fewer round half away from zero; none on overflow.

Effects: fail.

cut

gizlang
function cut(d: Dec, s: i64, mode: string): Dec

Toward zero at scale s (s <= decScale(d)), or toward -∞ (floor) or +∞ (ceil).

Effects: fail.

decRound

gizlang
function decRound(d: Dec, scale: i64): Option<Dec>

PostgreSQL's round(d, scale): half away from zero at scale; a negative scale rounds to a multiple of 10^-scale at scale 0. None on overflow.

Effects: fail.

decTrunc

gizlang
function decTrunc(d: Dec, scale: i64): Option<Dec>

PostgreSQL's trunc(d, scale): toward zero at scale; a negative scale truncates to a multiple of 10^-scale at scale 0.

Effects: fail.

fitsPrecision

gizlang
function fitsPrecision(d: Dec, p: i64): bool

Whether the value is in DECIMAL(p, s) once at scale s: at most p - s integer digits.

Effects: fail.

decSum

gizlang
function decSum(x: Dec, y: Dec): Dec

The exact sum past the limits too: a running total that PostgreSQL checks only at its end (decWithin).

Effects: fail.

decDifference

gizlang
function decDifference(x: Dec, y: Dec): Dec

x - y, exact past the limits too (decSum).

Effects: fail.

decAdd

gizlang
function decAdd(x: Dec, y: Dec): Option<Dec>

The exact sum; none past the limits.

Effects: fail.

decNeg

gizlang
function decNeg(x: Dec): Option<Dec>

-X, or none when it does not fit.

Effects: fail.

decSub

gizlang
function decSub(x: Dec, y: Dec): Option<Dec>

X - Y, or none when it does not fit.

Effects: fail.

decMul

gizlang
function decMul(x: Dec, y: Dec): Option<Dec>

The exact product at scale decScale(x) + decScale(y), rounded half away at scale 16383 past it (as PostgreSQL's numeric_mul); none past the limits.

Effects: fail.

decProduct

gizlang
function decProduct(x: Dec, y: Dec): Dec

The exact product at scale decScale(x) + decScale(y), past the limits too: a square inside variance, which PostgreSQL keeps whole (decSum).

Effects: fail.

decDiv

gizlang
function decDiv(x: Dec, y: Dec): Option<Dec>

x / y as PostgreSQL's numeric division: at its select_div_scale, rounded half away. None for a zero divisor (the caller reports it) and on overflow.

Effects: fail.

decDivTrunc

gizlang
function decDivTrunc(x: Dec, y: Dec): Option<Dec>

trunc(x / y) exactly, at scale 0 (PostgreSQL's div). None for a zero divisor and on overflow.

Effects: fail.

decMod

gizlang
function decMod(x: Dec, y: Dec): Option<Dec>

x - y × trunc(x / y): the sign of x, as SQL's % and MOD, at the larger scale. None for a zero divisor.

Effects: fail.

numberArith

gizlang
function numberArith(op: string, x: Dec, y: Dec): Option<Dec>

x op y (+ - * / %) as Oracle's NUMBER computes it: the exact result, or a quotient of 41 significant digits (one past what NUMBER keeps, so its rounding is the exact quotient's), then numberFit. None for a zero divisor and on overflow.

Effects: fail.

decCompareSum

gizlang
function decCompareSum(x: Dec, base: Dec, offset: Dec): i64

Compare x with base + offset without rounding the boundary.

Effects: fail.

decCompare

gizlang
function decCompare(x: Dec, y: Dec): i64

-1, 0 or 1, exactly.

Effects: fail.

decParts

gizlang
function decParts(d: Dec): Parts

D as a 128-bit whole part and two 19-digit fraction words, for a fast comparison (compareParts).

Effects: fail.

floatParts

gizlang
function floatParts(f: f64): Parts

The parts of a float with |f| < 2^127, exactly (from its bits, not its arithmetic).

Effects: fail.

compareParts

gizlang
function compareParts(a: Parts, b: Parts): i64

-1, 0 or 1 as A is less than, equal to or greater than B.

Effects: fail.

decCompareFloat

gizlang
function decCompareFloat(d: Dec, y: f64): i64

A decimal against a finite float, exactly.

Effects: fail.

intOf

gizlang
function intOf(d: Dec): Option<i64>

The value as an i64 when it is whole and fits one.

Effects: fail.

truncInt

gizlang
function truncInt(d: Dec): i64

Toward zero as an i64, saturating (SQLite's CAST of a huge number).

Effects: fail.

unitOf

gizlang
function unitOf(s: i64): f64

10^s as a float: what a coefficient at scale s is divided by.

sqrtScale

gizlang
function sqrtScale(x: Dec): i64

PostgreSQL's sqrt scale for x: 16 significant digits from its base-10000 weight, at least its scale, at most 1000.

Effects: fail.

decSqrt

gizlang
function decSqrt(x: Dec, scale: i64): Option<Dec>

The square root of x rounded half away at scale, as PostgreSQL's sqrt_var. None for a negative x.

Effects: fail.

decLn

gizlang
function decLn(x: Dec): Option<Dec>

ln(x) for x > 0 at PostgreSQL's scale.

Effects: fail.

decLog

gizlang
function decLog(b: Dec, x: Dec): Option<Dec>

The logarithm of x to base b, both > 0 and b not 1, at PostgreSQL's scale.

Effects: fail.

decExp

gizlang
function decExp(x: Dec): Option<Dec>

e^x at PostgreSQL's scale; none when it overflows.

Effects: fail.

decPow

gizlang
function decPow(x: Dec, y: Dec): Option<Dec>

x^y for finite x and y, where x is not negative or y is whole, and a zero x has y >= 0 (the caller reports the other cases), at PostgreSQL's scale (power_var); none when it overflows.

Effects: fail.

Constants

DEC_MAX_SCALE

gizlang
const DEC_MAX_SCALE = 16383

The largest scale (PostgreSQL's NUMERIC_DSCALE_MAX).

DEC_MAX_WHOLE

gizlang
const DEC_MAX_WHOLE = 131072

The most digits before the point: (NUMERIC_WEIGHT_MAX + 1) base-10000 digits.