The following table contains the elementary types currently defined by Numba.
Type Name | Alias | Result Type |
---|---|---|
boolean | b1 | uint8 (char) |
bool_ | b1 | uint8 (char) |
byte | u1 | unsigned char |
uint8 | u1 | uint8 (char) |
uint16 | u2 | uint16 |
uint32 | u4 | uint32 |
uint64 | u8 | uint64 |
char | i1 | signed char |
int8 | i1 | int8 (char) |
int16 | i2 | int16 |
int32 | i4 | int32 |
int64 | i8 | int64 |
float_ | f4 | float32 |
float32 | f4 | float32 |
double | f8 | float64 |
float64 | f8 | float64 |
complex64 | c8 | float complex |
complex128 | c16 | double complex |
Types can be used to specify the signature of a function:
@jit('f8(f8[:])')
def sum1d(array):
sum = 0.0
for i in range(array.shape[0]):
sum += array[i]
return sum
Types can also be used in Numba to declare local variables in a function:
@jit(locals=dict(array=double[:, :], scalar1=double))
def func(array):
scalar1 = array[0, 0] # scalar is declared double
scalar2 = double(array[0, 0])
Of course, declaring types in this example is unnecessary since the type inferencer knows the input type of array, and hence knows the type of array[i, j] to be the dtype of array.
Note
Type declarations or casts can be useful in cases where the type inferencer doesn’t know the type, or if you want to override the type inferencer’s rules (e.g. force 32-bit floating point precision).
Variables declared in the locals dict have a single type throughout the entire function. However, any variable not declared in locals can assume different types, just like in Python:
@jit
def variable_ressign(arg):
arg = 1.0
arg = "hello"
arg = object()
var = arg
var = "world"
However, there are some restrictions, namely that variables must have a unifyable type at control flow merge points. For example, the following code will not compile:
@jit
def incompatible_types(arg):
if arg > 10:
x = 1+2j
else:
x = 3.3
return x # ERROR! Inconsistent type for x!
This code is invalid because strings and integers are not compatible. However, if we do not read x after the if block, the code will compile fine, since it does not need to unify the type:
@jit
def compatible_types(arg):
if arg > 10:
x = "hello"
else:
x = arg
x = func()
return x
The same goes for loop carried dependencies and variables escaping loops, e.g.:
@jit
def incompatible_types2(N):
x = "hello"
for i in range(N):
print x # ERROR! Inconsistent type for x!
x = i
return x
@jit
def incompatible_types3(N):
x = "hello"
for i in range(N):
x = i
print x
return x # ERROR! Inconsistent type for x if N <= 0
Cases where the type inferencer doesn’t know the type is often when you call a Python function or method that is not a numba function and numba doesn’t otherwise recognize.
Numba allows you to obtain the type of a expression or variable through the typeof function in a Numba function. This type can then be used for instance to cast other values:
type = numba.typeof(x + y)
value = type(value)
When used outside of a Numba function, it returns the type the type inferencer would infer for that value:
>>> numba.typeof(1.0)
double
>>> numba.typeof(cmath.sqrt(-1))
complex128
Numba is in the process of being refactored to better define more complex types such as structs, pointers, strings and user defined classes. More on this soon...