类型系统

Taichi 支持常见的数据类型。每种类型都由一个字符表示,指明它的 类别精度位数,例如 i32f64

数据的 类别 可以是以下其中之一:

  • i 用于有符号整数,例如233,-666
  • u 用于无符号整数,例如233,666
  • f 用于浮点数,例如2.33, 1e-4

数据的 精度位数 可以是以下其中之一:

  • 8
  • 16
  • 32
  • 64

它表示存储数据时使用了多少 。位数越多,精度越高。

例如,下列是两种最常用的数据类型:

  • i32 表示一个32位有符号整数。
  • f32 表示一个32位浮点数。

支持的类型

目前,Taichi支持的基本类型有

  • int8 ti.i8
  • int16 ti.i16
  • int32 ti.i32
  • int64 ti.i64
  • uint8 ti.u8
  • uint16 ti.u16
  • uint32 ti.u32
  • uint64 ti.u64
  • float32 ti.f32
  • float64 ti.f64

注解

每种后端支持的类型分别有:

类型 CPU/CUDA OpenGL Metal
i8 OK N/A OK
i16 OK N/A OK
i32 OK OK OK
i64 OK EXT N/A
u8 OK N/A OK
u16 OK N/A OK
u32 OK N/A OK
u64 OK N/A N/A
f32 OK OK OK
f64 OK OK N/A

(OK:已支持,EXT:需要扩展支持,N/A:目前不支持)

注解

布尔类型使用 ti.i32 表示。

类型提升

不同类型间的二元运算将会发生数据类型提升,提升遵循 C 语言下的转换规则,例如:

  • i32 + f32 = f32 (integer + float = float)
  • i32 + i64 = i64 (less-bits + more-bits = more-bits)

简单地说,在发生数据提升时会尝试选择更精确的数据类型来包含结果值。

默认精度

默认情况下,所有的数值都具有32位精度。 例如,42 的类型为 ti.i323.14 的类型为 ti.f32

可以在 Taichi 初始化时,指定默认的整数和浮点精度( 分别通过 default_ipdefault_fp ):

ti.init(default_fp=ti.f32)
ti.init(default_fp=ti.f64)

ti.init(default_ip=ti.i32)
ti.init(default_ip=ti.i64)

另外需要注意的是,你可以在类型定义时使用 floatint 作为默认精度的别名,例如:

ti.init(default_ip=ti.i64, default_fp=ti.f32)

x = ti.var(float, 5)
y = ti.var(int, 5)
# 相当于:
x = ti.var(ti.f32, 5)
y = ti.var(ti.i64, 5)

def func(a: float) -> int:
    …

# 相当于:
def func(a: ti.f32) -> ti.i64:
    …

类型转换

隐式类型转换

警告

变量的类型在它 初始化时决定

当一个 低精度 变量被赋值给 高精度 变量时,它将被隐式提升为 高精度 类型,并且不会发出警告:

a = 1.7
a = 1
print(a)  # 1.0

当一个 高精度 变量被赋值给 低精度 类型时,它会被隐式向下转换为 低精度 类型,此时 Taichi 会发出警告:

a = 1
a = 1.7
print(a)  # 1

显式类型转换

你可以使用 ti.cast 在不同类型之间显式地强制转换标量值:

a = 1.7
b = ti.cast(a, ti.i32)  # 1
c = ti.cast(b, ti.f32)  # 1.0

同样,可以使用 int()float() 将标量值转换为默认精度的浮点或整数类型:

a = 1.7
b = int(a)    # 1
c = float(a)  # 1.0

向量和矩阵的类型转换

应用于向量/矩阵中的类型转换是逐元素的:

u = ti.Vector([2.3, 4.7])
v = int(u)              # ti.Vector([2, 4])
# 如果你使用的是 ti.i32 作为默认整型精度, 那么这相当于:
v = ti.cast(u, ti.i32)  # ti.Vector([2, 4])

位强制类型转换

使用 ti.bit_cast 将一个值按位转换为另一种数据类型。 基础位将在此转换中保留。 新类型的宽度必须与旧类型的宽度相同。 例如,不允许将 i32 转换成 f64。 请谨慎使用此操作。