Skip to content

feat: thirteen dtypes with NumPy 2.x promotion - #42

Merged
tannevaled merged 3 commits into
mainfrom
design/dtypes
Oct 9, 2026
Merged

tannevaled merged 3 commits into
mainfrom
design/dtypes

Conversation

@tannevaled

@tannevaled tannevaled commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Phase 2: dtypes. Design first (docs/design-dtypes.md), then the implementation.

What

Array holds bool, int8…int64, uint8…uint64, float32/64, complex64/128 — a runtime property, as in NumPy. The float64 storage and every float64 SIMD/multicore kernel are untouched; the other dtypes run generic loops dispatched by generated type switches (gen_dtypes.go → zz_dtypes_gen.go).

  • Promotion = numpy.result_type; Go scalars are weak (NEP 50): Scalar(1), and the *Scalar methods' float64.
  • New API: DType, ZerosOf/OnesOf/FullOf, FromSlice/Data/Item, AsType, AtComplex/SetComplex, Scalar, SumAll/ProdAll, Logical*, Any/All, Real/Imag/Conj/Angle.

Breaking

before after
comparisons → Float64 0/1 → Bool
Nonzero, ArgMaxAxis, ArgMinAxis → Float64 indices → Int64

MaskSelect/Where accept any dtype by truthiness, so old 0/1 masks still work. The only fleet consumer (go-embedded-ruby) uses none of these.

Verification

  • NumPy 2.5.3 fixtures (generators committed): all 169 result_type cells, weak scalars, unary/reduction result dtypes — all match (float16 read as float32, the documented difference).
  • 3,147 values over 47 operations × 13 dtypes with edge values (integer limits, NaN, ±Inf, −0): bit-exact where both sides round correctly, else ≤ 8 eps. Negative control: a sabotaged integer max fails 48.
  • Coverage 100% under the CI-identical gate (-race -coverpkg); vet for linux/386, linux/arm, js/wasm; the s390x test binary builds.
  • Float64 Add/Sum/Max/AddInto, interleaved A/B vs main: 0.93–1.02. The host was under load, so this shows no regression, not a gain.

Found on the way

NumPy's out-of-range float→int casts are platform-defined (arm64: +Inf→int8 is −1). Here they saturate on every platform — documented on AsType.

🤖 Generated with Claude Code

tannevaled and others added 2 commits October 9, 2026 15:26
…mpy promotion fixture

The design for Phase 2: why the dtype is a runtime property of the one
Array type rather than a generic Dense[T] (promotion picks the result type
from both operands, which a generic method cannot express; the consumers
are dynamic; nothing existing breaks), the storage layout that leaves the
float64 hot path untouched, the NumPy semantics and the deliberate
differences, the two breaking changes, and the delivery order.

testdata/promotion.json is generated from NumPy 2.5.3 by
testdata/promotion.py: the 13x13 result_type table, weak-scalar results,
unary ufunc and reduction dtypes. The implementation will be tested
against every cell.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Array now holds bool, the eight integer types, float32/64 and
complex64/128, chosen at run time as in NumPy. Float64 storage and every
float64 kernel are untouched; the other dtypes live in a typed slice and
run generic loops, one per element type, picked by type switches that
gen_dtypes.go generates.

Promotion is numpy.result_type; Go scalars are weak as Python scalars are
under NEP 50 (Scalar, and the *Scalar methods' float64). Integer true
division gives float64; sums and products accumulate in int64/uint64;
float ufuncs on integers give float32 where NumPy gives float16.

New: DType, ZerosOf/OnesOf/FullOf, FromSlice/Data/Item, AsType,
AtComplex/SetComplex, Scalar, SumAll/ProdAll, LogicalNot/And/Or/Xor,
Any/All, Real/Imag/Conj/Angle.

Breaking: comparisons return Bool; Nonzero and ArgMax/ArgMinAxis return
Int64 indices. MaskSelect and Where accept any dtype by truthiness, so the
old 0/1 float masks keep working. The float64 comparison and arg-axis
kernels they used are removed.

Checked against NumPy 2.5.3: all 169 result_type cells, weak scalars, and
the result dtype of unary ufuncs and reductions; 3,147 values over 47
operations on every dtype with edge values (bit-exact where both sides
round correctly; a sabotaged integer max fails 48). Coverage 100% under the
CI gate. Float64 Add/Sum/Max/AddInto A/B against main, interleaved:
within noise (0.93-1.02).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tannevaled tannevaled changed the title docs: dtype design (runtime dtype, NumPy 2.x promotion) feat: thirteen dtypes with NumPy 2.x promotion Oct 9, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tannevaled
tannevaled merged commit 3217f28 into main Oct 9, 2026
12 checks passed
@tannevaled
tannevaled deleted the design/dtypes branch October 9, 2026 19:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant