Skip to content

Commit fb92090

Browse files
authored
Merge pull request #97 from dupontcyborg/full-arange-default-dtype
Updated default dtypes for full and arange
2 parents e57caeb + ea2369f commit fb92090

File tree

3 files changed

+34
-26
lines changed

3 files changed

+34
-26
lines changed

benchmarks/src/validation.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1450,8 +1450,9 @@ export async function validateBenchmarks(specs: BenchmarkCase[]): Promise<void>
14501450
'unravel_index',
14511451
'random_permutation',
14521452
]);
1453-
// Integer creation functions: we return int32, NumPy returns int64
1454-
const INT_CREATION_OPS = new Set(['arange', 'full', 'full_like']);
1453+
// Integer creation functions: full/full_like return int32 (we
1454+
// diverge from NumPy's int64 to avoid BigInt for in-range fills).
1455+
const INT_CREATION_OPS = new Set(['full', 'full_like']);
14551456
const isIndexOp = INDEX_OPS.has(spec.operation);
14561457
const isIntCreation = INT_CREATION_OPS.has(spec.operation);
14571458
if (
@@ -1460,6 +1461,12 @@ export async function validateBenchmarks(specs: BenchmarkCase[]): Promise<void>
14601461
(npDtype === 'int64' || npDtype === 'uint64')
14611462
) {
14621463
// Accepted: index ops return float64 for JS ergonomics
1464+
} else if (
1465+
spec.operation === 'arange' &&
1466+
tsDtype === 'float64' &&
1467+
npDtype === 'int64'
1468+
) {
1469+
// Accepted: arange defaults to float64 (matches zeros/ones/linspace)
14631470
} else if (isIntCreation && tsDtype === 'int32' && npDtype === 'int64') {
14641471
// Accepted: int32 is our int64 equivalent for non-BigInt JS numbers
14651472
} else if (

src/core/creation.ts

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ export function full(
8686
} else if (typeof fill_value === 'boolean') {
8787
actualDtype = 'bool';
8888
} else if (Number.isInteger(fill_value)) {
89-
// Integers outside int32 range default to float64 (matches NumPy)
90-
actualDtype = fill_value >= -2147483648 && fill_value <= 2147483647 ? 'int32' : 'float64';
89+
// Integer fill: int32 if it fits, otherwise int64 for the wider range.
90+
actualDtype = fill_value >= -2147483648 && fill_value <= 2147483647 ? 'int32' : 'int64';
9191
} else {
9292
actualDtype = DEFAULT_DTYPE;
9393
}
@@ -283,18 +283,9 @@ export function arange(start: number, stop?: number, step: number = 1, dtype?: D
283283

284284
const length = Math.max(0, Math.ceil((actualStop - actualStart) / step));
285285

286-
// Infer dtype from arguments: all integers that fit in int32 → int32, else float64
287-
const INT32_MAX = 2147483647;
288-
const INT32_MIN = -2147483648;
289-
const allInt =
290-
Number.isInteger(actualStart) && Number.isInteger(actualStop) && Number.isInteger(step);
291-
const lastVal = length > 0 ? actualStart + (length - 1) * step : actualStart;
292-
const fitsInt32 =
293-
actualStart >= INT32_MIN &&
294-
actualStart <= INT32_MAX &&
295-
lastVal >= INT32_MIN &&
296-
lastVal <= INT32_MAX;
297-
const actualDtype = dtype ?? (allInt && fitsInt32 ? 'int32' : DEFAULT_DTYPE);
286+
// Default to float64 for consistency with zeros/ones/empty/linspace.
287+
// Diverges from NumPy (which returns int64 for integer args) to avoid BigInt.
288+
const actualDtype = dtype ?? DEFAULT_DTYPE;
298289

299290
// bool arange only valid for length ≤ 2: [False] or [False, True]
300291
if (actualDtype === 'bool' && length > 2) {

tests/unit/creation.test.ts

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -77,22 +77,26 @@ describe('Array Creation Functions', () => {
7777
expect(arr.toArray()).toEqual([]);
7878
});
7979

80-
it('infers int32 dtype for integer args', () => {
81-
expect(arange(10).dtype).toBe('int32');
80+
it('defaults to float64 dtype for integer args', () => {
81+
expect(arange(10).dtype).toBe('float64');
8282
});
8383

84-
it('infers int32 dtype for all-integer start/stop/step', () => {
85-
expect(arange(0, 10, 1).dtype).toBe('int32');
84+
it('defaults to float64 dtype for all-integer start/stop/step', () => {
85+
expect(arange(0, 10, 1).dtype).toBe('float64');
8686
});
8787

88-
it('infers float64 dtype for float step', () => {
88+
it('defaults to float64 dtype for float step', () => {
8989
expect(arange(0, 10, 0.5).dtype).toBe('float64');
9090
});
9191

92-
it('infers float64 dtype when args overflow int32', () => {
92+
it('defaults to float64 dtype when args overflow int32', () => {
9393
expect(arange(0, 3e9, 1e8).dtype).toBe('float64');
9494
});
9595

96+
it('honors explicit dtype override', () => {
97+
expect(arange(0, 10, 1, 'int32').dtype).toBe('int32');
98+
});
99+
96100
it('respects explicit dtype over inference', () => {
97101
expect(arange(10, undefined, 1, 'float64').dtype).toBe('float64');
98102
});
@@ -348,16 +352,22 @@ describe('Array Creation Functions', () => {
348352
expect(arr.dtype).toBe('float64');
349353
});
350354

351-
it('infers float64 dtype for overflow fill value', () => {
352-
expect(full([2], 3e9).dtype).toBe('float64');
355+
it('infers int64 dtype for overflow fill value', () => {
356+
expect(full([2], 3e9).dtype).toBe('int64');
353357
});
354358

355359
it('infers int32 dtype for max int32 fill value', () => {
356360
expect(full([2], 2147483647).dtype).toBe('int32');
357361
});
358362

359-
it('infers float64 dtype for int32 overflow fill value', () => {
360-
expect(full([2], 2147483648).dtype).toBe('float64');
363+
it('infers int64 dtype for int32 overflow fill value', () => {
364+
expect(full([2], 2147483648).dtype).toBe('int64');
365+
});
366+
367+
it('stores correct value when inferring int64 from a JS number', () => {
368+
const arr = full([2], 3e9);
369+
expect(arr.get([0])).toBe(3000000000n);
370+
expect(arr.get([1])).toBe(3000000000n);
361371
});
362372
});
363373

0 commit comments

Comments
 (0)