Data Types
The DataType enum, per-array typing, type casting, mixed precision, and migration from global data type
One of the most significant changes in M2.1 is the move from a global data type to per-array data types. Every INDArray now carries its own DataType, and operations are type-aware. This page covers the full DataType enum, how to create typed arrays, how to cast between types, and how to take advantage of mixed precision training.
The DataType Enum
All numeric types in ND4J are represented by the enum org.nd4j.linalg.api.buffer.DataType. Import it with:
import org.nd4j.linalg.api.buffer.DataType;Floating-Point Types
Floating-point types are used for neural network weights, activations, and most numeric computation.
DOUBLE
64
IEEE 754 double-precision float. Highest precision, largest memory footprint.
FLOAT
32
IEEE 754 single-precision float. Default type. Best balance of precision and performance on most hardware.
FLOAT16
16
Half-precision float. Reduced memory and bandwidth; supported on modern NVIDIA GPUs and some CPUs. Same constant as the deprecated HALF.
BFLOAT16
16
Brain float 16. Same 8-bit exponent range as FLOAT, but only 7 mantissa bits. Numerically safer than FLOAT16 for training. Supported on TPUs, A100/H100 GPUs, and recent Intel CPUs.
Signed Integer Types
INT64
64
64-bit signed integer. Same constant as the deprecated LONG.
INT32
32
32-bit signed integer. Same constant as the deprecated INT.
INT16
16
16-bit signed integer. Same constant as the deprecated SHORT.
INT8
8
8-bit signed integer, range −128 to 127. Same constant as the deprecated BYTE.
Unsigned Integer Types
UINT64
64
UINT32
32
UINT16
16
UINT8
8 — range 0 to 255. Same constant as the deprecated UBYTE.
Other Types
BOOL
Boolean — stores true/false per element. Used by comparison ops that return masks.
UTF8
Variable-length UTF-8 string data. Used for label arrays and metadata.
COMPRESSED
Internal placeholder for compressed arrays. Not for direct use.
UNKNOWN
Sentinel value. Indicates an uninitialized or invalid type.
Deprecated Aliases
Several names from earlier releases are still present in the enum but are annotated @Deprecated. They map to the same underlying constant as their preferred replacement.
HALF
FLOAT16
LONG
INT64
INT
INT32
SHORT
INT16
BYTE
INT8
UBYTE
UINT8
FLOAT16 and HALF are literally the same enum constant — FLOAT16 is a static field on the enum that points to HALF. The same relationship holds for each deprecated/preferred pair. Both names work identically at runtime, but new code should use the preferred names to keep intent clear.
Memory Footprint
Every element of an INDArray occupies a fixed number of bytes determined by its DataType. Understanding this is essential for planning GPU memory budgets and comparing model footprints.
DOUBLE / INT64 / UINT64
8
FLOAT / INT32 / UINT32
4
FLOAT16 / BFLOAT16 / INT16 / UINT16
2
INT8 / UINT8 / BOOL
1
A 1000-element array uses 8 KB as DOUBLE, 4 KB as FLOAT, and 2 KB as FLOAT16 or BFLOAT16. For a 100M-parameter model this difference is 800 MB vs 400 MB vs 200 MB — a decisive factor in whether a model fits in GPU memory.
Migration from Beta4 and Earlier
In beta4 and all earlier releases, data type was a global, process-wide setting applied to all arrays:
In M2.1, DataBuffer.Type has been removed entirely. Each INDArray carries its own DataType, and creation methods accept it as an explicit argument. The global concept still exists as a default (see below), but it is no longer the only mechanism.
What Changed
Type class
DataBuffer.Type
DataType
Set global type
Nd4j.setDataType(DataBuffer.Type.X)
Nd4j.setDefaultDataTypes(DataType.X, DataType.Y)
Per-array type
Not supported
Every INDArray has a DataType
Type checking
N/A
arr.dataType()
Casting
N/A
arr.castTo(DataType.X)
Replace every DataBuffer.Type reference in your codebase:
Default Data Type
The default type for newly created arrays is FLOAT. When you call a creation method without an explicit DataType argument, ND4J uses the current default.
You can change the default at application startup with Nd4j.setDefaultDataTypes. It accepts two arguments: the default floating-point type and the default integer type.
Call setDefaultDataTypes once at startup, before any array creation. Changing it mid-run can produce inconsistent types that are hard to debug.
Creating Typed Arrays
All Nd4j creation methods accept a DataType as their first argument. Pass the type explicitly whenever you need a specific type, regardless of what the default is.
Zeros, Ones, and Value-Filled Arrays
Random Arrays
Linspace
From Java Arrays
Type inference uses the Java primitive type when creating from Java arrays. To force a specific type, create with an explicit DataType and then fill, or create and cast:
Checking the Type of an Array
Call arr.dataType() to retrieve the DataType of any INDArray:
Casting Between Types
To convert an INDArray from one DataType to another, call castTo. This always returns a new array (a copy) in the target type. The original is not modified.
Precision Loss
Casting from a higher-precision type to a lower-precision type loses information:
This is expected and intentional when using reduced precision. For training stability, keep high-precision master copies and cast only for the forward/backward pass.
Integer Truncation
Casting a floating-point array to an integer type truncates (not rounds) the fractional part:
Type Matching for Operations
In M2.1, the two operands of a binary operation must have the same DataType. If types differ, ND4J throws an exception:
This is a deliberate design choice: silent implicit promotion (as in many scripting languages) hides bugs where the user accidentally mixes types and gets unexpected precision or memory use.
Solution: cast one operand before the operation:
Choose which direction to cast based on whether you need the precision of DOUBLE or the memory savings of FLOAT.
Type-Safe Helper Pattern
When writing utility code that must accept any numeric type, check and cast defensively:
Mixed Precision Training
Mixed precision training uses lower-precision types (typically FLOAT16 or BFLOAT16) for most computation while keeping higher-precision master weights to accumulate gradients accurately. The result is significantly lower GPU memory use and higher throughput on hardware with native half-precision support (NVIDIA Volta and later, AMD RDNA2+).
Strategy
Master weights are stored as
FLOAT(32-bit).Before each forward pass, cast the master weights to
FLOAT16orBFLOAT16.The forward and backward passes execute in half precision.
Gradients are cast back to
FLOATand accumulated into the master weights.The optimizer step runs in
FLOAT.
FLOAT16 vs BFLOAT16
Both use 2 bytes per element, but they allocate those bits differently:
FLOAT16
5
10
~65,504
BFLOAT16
8
7
~3.4 × 10^38 (same as FLOAT)
FLOAT16 offers higher precision for values in its range, but overflows easily — activations or gradients that exceed ~65,504 become Inf. This requires loss scaling (multiplying the loss by a large constant before the backward pass) to keep gradients in range.
BFLOAT16 has the same exponent range as FLOAT, so it does not overflow under conditions that FLOAT would not overflow. Gradients stay finite without loss scaling in most cases. The trade-off is lower mantissa precision (~2 decimal digits vs ~3 for FLOAT16).
Recommendation: prefer BFLOAT16 when your hardware supports it. It requires less engineering overhead to use safely.
Setting a Default for Half-Precision Training
Reference: DataType Summary
DOUBLE
8
Yes
64-bit IEEE 754. Use for scientific computing where precision matters.
FLOAT
4
Yes
32-bit IEEE 754. Default. Good choice for most training workloads.
FLOAT16
2
Yes
16-bit half. GPU-accelerated mixed precision. Requires loss scaling. HALF is deprecated alias.
BFLOAT16
2
Yes
Brain float. Same exponent range as FLOAT. Preferred for training without loss scaling.
INT64
8
No
64-bit signed. LONG is deprecated alias.
INT32
4
No
32-bit signed. INT is deprecated alias.
INT16
2
No
16-bit signed. SHORT is deprecated alias.
INT8
1
No
8-bit signed, −128 to 127. BYTE is deprecated alias.
UINT64
8
No
64-bit unsigned.
UINT32
4
No
32-bit unsigned.
UINT16
2
No
16-bit unsigned.
UINT8
1
No
8-bit unsigned, 0 to 255. UBYTE is deprecated alias.
BOOL
1
No
Boolean. Returned by comparison ops.
UTF8
variable
No
String data. Used for label arrays.
Key API Signatures
Last updated
Was this helpful?