开发者
资源

简介

类型转换分为隐式转换和显式转换。隐式转换由系统在类型不匹配时自动执行。

显式转换通过调用类型转换API主动完成,API将输入数据从源类型转换为目标类型,并返回转换结果。

转换过程遵循规定的处理规则。类型转换的结果受舍入模式和饱和模式的影响。浮点数的表示方式和舍入规则请见类型转换

隐式转换

隐式转换是指在不显式指定目标类型的情况下,系统自动将数据从源类型转换为目标类型的行为。

以下是一个隐式转换的示例。
1
2
int32_t a;
a = 2.2f; // a = 2
表1 隐式转换规则

输入数据类型

输出数据类型

舍入规则与特殊值说明

整型

int8_t/uint8_t/int16_t/uint16_t/int32_t/uint32_t/int64_t/uint64_t

整型

int8_t/uint8_t/int16_t/uint16_t/int32_t/uint32_t/int64_t/uint64_t

舍入规则遵循CAST_TRUNC

浮点型变量

float

整型

int32_t/uint32_t/int64_t/uint64_t

舍入规则遵循CAST_TRUNC

宽范围数据转成窄范围数据时:

  • 如果输入为+inf,或者超出该类型所能表示的最大值,转换结果为最大值。
  • 如果输入为-inf,或者小于该类型所能表示的最小值,转换结果为最小值。
  • 如果输入为nan,转换结果为0。

half

int32_t/uint32_t

bfloat16_t

int32_t/uint32_t

整型

int32_t

浮点型变量

float/half/bfloat16_t

舍入规则遵循CAST_RINT

宽范围数据转成窄范围数据时:

  • 如果输入超出该类型所能表示的范围,转换结果为对应符号的inf值。

uint32_t

float/half/bfloat16_t

int64_t

float

uint64_t

float

浮点型变量

float

浮点型变量

half/bfloat16_t

舍入规则遵循CAST_RINT

宽范围数据转成窄范围数据时:

  • 如果输入超出该类型所能表示的范围,转换结果为对应符号的inf值。
  • 如果输入为nan,转换结果为nan。

half

float/bfloat16_t

bfloat16_t

float/half

隐式转换示例如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// int8_t转uint8_t
int8_t a = -100;
uint8_t b = a; // b = 156

// half转int32_t
half a = 60000.6;
int32_t b = a; // b = 60000

// int32_t转half
int32_t a = 100000;
half b = a; // b = inf,100000超出half类型能表示的范围

// float转half
float a = -100000.0f;
half b = a; // b = -inf,-100000.0f超出half类型能表示的范围

舍入模式

舍入模式控制转换过程中精度损失的处理方式。

表2 类型转换类接口支持的舍入模式

舍入模式

描述

接口名格式

CAST_RINT

四舍六入五成双取整

srctype2dsttype_rn

CAST_FLOOR

向下取整

SrcType2DstType_rd

CAST_CEIL

向上取整

srctype2dsttype_ru

CAST_ROUND

四舍五入取整

srctype2dsttype_rna

CAST_TRUNC

向零取整

srctype2dsttype_rz

CAST_ODD

最近邻奇数舍入

srctype2dsttype_ro

CAST_HYBRID

目前特指输出结果为hi8数据时,会用到的一种随机舍入

srctype2dsttype_rh

上表说明了各个输入模式对应的接口名格式,其中srctype表示输入源操作数类型,dsttype表示输出目标类型。例如:float类型转成half类型并使用CAST_RINT模式进行舍入接口名为__float2half_rn。

饱和行为

饱和行为控制对nan、inf特殊值以及转换后超出目标类型范围结果的处理方式。

表3 饱和行为的模式说明

模式

描述

接口名格式

非饱和模式

默认模式。

  • 如果输入超出该类型所能表示的范围,转换结果为对应符号的inf值。
  • 如果输入为nan,转换结果为nan。

srctype2dsttype_r[xx]

饱和模式

饱和模式下:

  • 如果输入为+inf,或者超出该类型所能表示的最大值,转换结果为最大值。
  • 如果输入为-inf,或者小于该类型所能表示的最小值,转换结果为最小值。
  • 如果输入为nan,转换结果为0。

srctype2dsttype_r[xx]_sat

控制饱和行为的方式

饱和行为受寄存器CTRL[60]、CTRL[48]和接口功能同时控制,SIMD与SIMT混合编程场景下,CTRL寄存器的设置请参考SetCtrlSpr(ISASI)接口。SIMT编程场景暂不支持设置CTRL寄存器。

宽范围数据转成窄范围数据且转换的目标类型不是float时,包括float转half、float转bfloat16_t、bfloat16_t转half、float或half转hifloat8_t、fp8_e4m3fn_t或fp8_e5m2_t,接口的饱和行为受硬件寄存器CTRL[60]和CTRL[48]的影响。具体行为如下:

  • 当CTRL[60] = 0时,饱和行为受接口独立控制。
    • 后缀__sat的接口转换结果为饱和模式。
    • 不带__sat后缀的接口转换结果为非饱和模式。
  • 当CTRL[60] = 1时,饱和行为只受CTRL[48]全局控制。
    • 当CTRL[48] = 1时,接口转换结果为非饱和模式。
    • 当CTRL[48] = 0时,接口转换结果为饱和模式。
表4 宽范围数据转窄范围数据的最终饱和行为

Ctrl[60]

Ctrl[48]

接口名格式

最终饱和行为

0

/

不带__sat

非饱和

1

1

/

非饱和

0

/

__sat

饱和

1

0

/

饱和

对如下两种情况,饱和行为只受ctrl[48]控制。

  • 窄范围数据转换为宽范围数据,且转换的目的操作数类型不是float,即half转bfloat16_t、hifloat8_t转half。
  • half转half、bfloat16_t转bfloat16_t。

具体行为如下:

  • 当CTRL[48] = 1时,接口转换结果为非饱和模式。
  • 当CTRL[48] = 0时,接口转换结果为饱和模式。
表5 窄范围数据转宽范围数据、同类型数据转换最终饱和行为

Ctrl[60]

Ctrl[48]

最终饱和行为

/

1

非饱和

/

0

饱和

对于转换的目标类型为float的情况,所有类型转换接口只支持非饱和模式。浮点数转换为整数时,转换结果均采用饱和模式。

数据类型转换规则示例

表6 精度转换规则示例

输入数据类型

输出数据类型

精度转换规则示例

float

float

将src按照舍入模式(精度转换处理模式,参见表2)取整,仍以float格式存入dst中。

示例:输入0.5,

CAST_RINT模式输出0.0,CAST_FLOOR模式输出0.0,CAST_CEIL模式输出1.0,CAST_ROUND模式输出1.0,CAST_TRUNC模式输出0.0。

half

示例1:输入0.5 + 2-12,写成float的表示形式:2-1 * (1 + 2-11),因此E = -1 + 127 = 126,M = 2-11

half的指数位可以表示出2-1,E = -1 + 15 = 14,但half只有10 bit尾数位,因此要进行舍入。

CAST_RINT模式舍入得尾数0000000000,E = 14,M = 0,最终表示的结果为0.5;

CAST_FLOOR模式舍入得尾数0000000000,E = 14,M = 0,最终表示的结果为0.5;

CAST_CEIL模式舍入得尾数0000000001,E = 14,M = 2-10,最终表示的结果为0.5 + 2-11

CAST_ROUND模式舍入得尾数0000000001,E = 14,M = 2-10,最终表示的结果为0.5 + 2-11

CAST_TRUNC模式舍入得尾数0000000000,E = 14,M = 0,最终表示的结果为0.5;

CAST_ODD模式舍入得尾数0000000001,E = 14,M = 2-10,最终表示的结果为0.5 + 2-11

float转half的最终饱和行为请见表4

示例2:输入inf,饱和模式输出65504,非饱和模式输出inf。

示例3:输入-inf,饱和模式输出-65504,非饱和模式输出-inf。

示例3:输入nan,饱和模式输出0,非饱和模式输出nan。

bfloat16_t

示例1:输入0.5+ 2-9 + 2-11 ,写成float的表示形式:2-1 * (1 + 2-8 + 2-10),因此E = -1 + 127 = 126,M = 2-8 + 2-10

bfloat16_t的指数位位数和float的相同,有E = 126,但bfloat16_t只有7bit尾数位,因此要进行舍入。

CAST_RINT模式舍入得尾数0000001,E = 126,M = 2-7,最终表示的结果为0.5 + 2-8

CAST_FLOOR模式舍入得尾数0000000,E = 126,M = 0,最终表示的结果为0.5;

CAST_CEIL模式舍入得尾数0000001,E = 126,M = 2-7,最终表示的结果为0.5 + 2-8

CAST_ROUND模式舍入得尾数0000001,E = 126,M = 2-7,最终表示的结果为0.5 + 2-8

CAST_TRUNC模式舍入得尾数0000000,E = 126,M = 0,最终表示的结果为0.5。

float转bfloat16_t的最终饱和行为请见表4

示例2:输入inf,饱和模式输出约3.39*1038,非饱和模式输出inf。

示例3:输入-inf,饱和模式输出约-3.39*1038,非饱和模式输出-inf。

示例3:输入nan,饱和模式输出0,非饱和模式输出nan。

int32_t

示例1:输入222 + 0.5,CAST_RINT模式输出222,CAST_FLOOR模式输出222,CAST_CEIL模式输出222 + 1,CAST_ROUND模式输出222 + 1,CAST_TRUNC模式输出222

示例2:输入inf,输出231-1。

示例3:输出-inf,输出2-31

示例4:输入nan,输出0。

uint32_t

示例1:输入222 + 0.5,CAST_RINT模式输出222,CAST_FLOOR模式输出222,CAST_CEIL模式输出222 + 1,CAST_ROUND模式输出222 + 1,CAST_TRUNC模式输出222

示例2:输入inf,输出232-1。

示例3:输出-inf,输出0。

示例4:输入nan,输出0。

int64_t

示例1:输入222 + 0.5,CAST_RINT模式输出222,CAST_FLOOR模式输出222,CAST_CEIL模式输出222 + 1,CAST_ROUND模式输出222 + 1,CAST_TRUNC模式输出222

示例2:输入inf,输出232-1。

示例3:输出-inf,输出0。

示例4:输入nan,输出0。

uint64_t

示例1:输入222 + 0.5,CAST_RINT模式输出222,CAST_FLOOR模式输出222,CAST_CEIL模式输出222 + 1,CAST_ROUND模式输出222 + 1,CAST_TRUNC模式输出222

示例2:输入inf,输出264-1。

示例3:输出-inf,输出0。

示例4:输入nan,输出0。

hifloat8_t

将src按照舍入模式取整,以hifloat8_t格式(溢出默认按照饱和处理)存入dst中。

示例:输入1.75,CAST_ROUND模式输出2;CAST_HYBRID参考表9输出。

fp8_e4m3fn_t

将src按照舍入模式取整,以fp8_e4m3fn_t格式(溢出默认按照饱和处理)存入dst中。

示例:输入2.5,CAST_RINT模式输出2。

fp8_e5m2_t

将src按照舍入模式取整,以fp8_e5m2_t格式(溢出默认按照饱和处理)存入dst中。

示例:输入2.5,CAST_RINT模式输出2。

half

half

将src按照舍入模式取整,仍以half格式存入dst中。

示例:输入0.5,

CAST_RINT模式输出0.0,CAST_FLOOR模式输出0.0,CAST_CEIL模式输出1.0,CAST_ROUND模式输出1.0,CAST_TRUNC模式输出0.0。

float

不存在精度转换问题,舍入模式不起作用。

示例1:输入1.5 - 2-10,输出1.5 - 2-10

half转float仅支持非饱和模式。

示例2:输入inf,输出inf。

示例3:输入-inf,输出-inf。

示例4:输入nan,输出nan。

bfloat16_t

示例1:输入0.5+ 2-9 + 2-11 ,写成half的表示形式:2-1 * (1 + 2-8 + 2-10),因此E = -1 + 15 = 14,M = 2-8 + 2-10

bfloat16_t的指数位可以表示出2-1,E = -1 + 127 = 126,但bfloat16_t只有7bit尾数位,因此要进行舍入。

CAST_RINT模式舍入得尾数0000001,E = 126,M = 2-7,最终表示的结果为0.5 + 2-8

CAST_FLOOR模式舍入得尾数0000000,E = 126,M = 0,最终表示的结果为0.5。

CAST_CEIL模式舍入得尾数0000001,E = 126,M = 2-7,最终表示的结果为0.5 + 2-8

CAST_ROUND模式舍入得尾数0000001,E = 126,M = 2-7,最终表示的结果为0.5 + 2-8

CAST_TRUNC模式舍入得尾数0000000,E = 126,M = 0,最终表示的结果为0.5。

half转bfloat16_t的最终饱和行为请见表5

示例2:输入inf,饱和模式输出约3.39*1038,非饱和模式输出inf。

示例3:输入-inf,饱和模式输出约-3.39*1038,非饱和模式输出-inf。

示例4:输入nan,饱和模式输出0,非饱和模式输出nan。

int32_t

示例1:输入29 + 0.5,CAST_RINT模式输出29,CAST_FLOOR模式输出29,CAST_CEIL模式输出29 + 1,CAST_ROUND模式输出29 + 1,CAST_TRUNC模式输出29

示例2:输入inf,输出231-1。

示例3:输出-inf,输出2-31

示例4:输入nan,输出0。

uint32_t

示例1:输入29 + 0.5,CAST_RINT模式输出29,CAST_FLOOR模式输出29,CAST_CEIL模式输出29 + 1,CAST_ROUND模式输出29 + 1,CAST_TRUNC模式输出29

示例2:输入inf,输出232-1。

示例3:输出-inf,输出0。

示例4:输入nan,输出0。

hifloat8_t

将src按照舍入模式取整,以hifloat8_t格式(溢出默认按照饱和处理)存入dst中。

示例:输入1.75,

CAST_ROUND模式输出2,CAST_HYBRID模式参考表10输出。

bfloat16_t

bfloat16_t

将src按照舍入模式取整,仍以bfloat16_t格式存入dst中。

示例:输入0.5,

CAST_RINT模式输出0.0,CAST_FLOOR模式输出0.0,CAST_CEIL模式输出1.0,CAST_ROUND模式输出1.0,CAST_TRUNC模式输出0.0。

float

不存在精度转换问题,舍入模式不起作用。

示例1:输入1.5 - 2-6,输出1.5 - 2-6

bfloat16_t转float仅支持非饱和模式。

示例2:输入inf,输出inf。

示例3:输入-inf,输出-inf。

示例4:输入nan,输出nan。

half

示例1:输入1.5 - 2-6,输出1.5 - 2-6

bfloat16转half的最终饱和行为请见表4

示例2:输入inf,饱和模式输出65504,非饱和模式输出inf。

示例3:输入-inf,饱和模式输出-65504,非饱和模式输出-inf。

示例3:输入nan,饱和模式输出0,非饱和模式输出nan。

int32_t

示例1:输入26 + 0.5,CAST_RINT模式输出26,CAST_FLOOR模式输出26,CAST_CEIL模式输出26 + 1,CAST_ROUND模式输出26 + 1,CAST_TRUNC模式输出26

示例2:输入inf,输出231-1。

示例3:输出-inf,输出2-31

示例4:输入nan,输出0。

uint32_t

示例1:输入26 + 0.5,CAST_RINT模式输出26,CAST_FLOOR模式输出26,CAST_CEIL模式输出26 + 1,CAST_ROUND模式输出26 + 1,CAST_TRUNC模式输出26

示例2:输入inf,输出232-1。

示例3:输出-inf,输出0。

示例4:输入nan,输出0。

hifloat8_t

float

将src以float格式存入dst中,不存在精度转换问题,无舍入模式。

示例:输入2,输出2。

half

将src以half格式存入dst中,不存在精度转换问题,无舍入模式。

示例:输入2,输出2。

fp8_e4m3fn_t

float

将src以float格式存入dst中,不存在精度转换问题,无舍入模式。

示例:输入2,输出2。

fp8_e5m2_t

float

将src以float格式存入dst中,不存在精度转换问题,无舍入模式。

示例:输入2,输出2。

int32_t

float

示例1:输入225 + 3,写成float的表示形式:225 * (1 + 2-24 + 2-25),要求E = 25 + 127 = 152,M = 2-24 + 2-25

由于float只有23bit尾数位,因此要进行舍入。

CAST_RINT模式舍入得尾数00000000000000000000001,E = 152,M = 2-23,最终表示的结果为225 + 4;

CAST_FLOOR模式舍入得尾数00000000000000000000000,E = 152,M = 0,最终表示的结果为225

CAST_CEIL模式舍入得尾数00000000000000000000001,E = 152,M = 2-23,最终表示的结果为225 + 4;

CAST_ROUND模式舍入得尾数00000000000000000000001,E = 152,M = 2-23,最终表示的结果为225 + 4;

CAST_TRUNC模式舍入得尾数00000000000000000000000,E = 152,M = 0,最终表示的结果为225

half

示例1:输入212 + 3,写成half的表示形式:212 *(1 + 2-11 + 2-12),要求E = 12 + 15 = 27,M = 2-11 + 2-12

由于half只有10bit尾数位,因此要进行舍入。

CAST_RINT模式舍入得尾数0000000001,E = 27,M = 2-10,最终表示的结果为212 + 4;

CAST_FLOOR模式舍入得尾数0000000000,E = 27,M = 0,最终表示的结果为212

CAST_CEIL模式舍入得尾数0000000001,E = 27,M = 2-10,最终表示的结果为212+ 4;

CAST_ROUND模式舍入得尾数0000000001,E = 27,M =2-10,最终表示的结果为212 + 4;

CAST_TRUNC模式舍入得尾数0000000000,E = 27,M = 0,最终表示的结果为212

示例2:输入231 - 1,SAT模式返回65504.0,NO_SAT模式返回inf。

示例3:输入-231,SAT模式返回-65504.0,NO_SAT模式返回-inf。

bfloat16_t

示例1:输入29 + 3,写成bfloat16_t的表示形式:29 *(1 + 2-8 + 2-9),要求E = 9 + 127 = 136,M = 2-8 + 2-9

由于bfloat16_t只有7bit尾数位,因此要进行舍入。

CAST_RINT模式舍入得尾数0000001,E = 136,M = 2-7,最终表示的结果为29 + 4;

CAST_FLOOR模式舍入得尾数0000000,E = 136,M = 0,最终表示的结果为29

CAST_CEIL模式舍入得尾数0000001,E = 136,M = 2-7,最终表示的结果为29+ 4;

CAST_ROUND模式舍入得尾数0000001,E = 136,M = 2-7,最终表示的结果为29 + 4;

CAST_TRUNC模式舍入得尾数0000000,E = 136,M = 0,最终表示的结果为29

uint32_t

float

示例1:输入225 + 3,写成float的表示形式:225 * (1 + 2-24 + 2-25),要求E = 25 + 127 = 152,M = 2-24 + 2-25

由于float只有23bit尾数位,因此要进行舍入。

CAST_RINT模式舍入得尾数00000000000000000000001,E = 152,M = 2-23,最终表示的结果为225 + 4;

CAST_FLOOR模式舍入得尾数00000000000000000000000,E = 152,M = 0,最终表示的结果为225

CAST_CEIL模式舍入得尾数00000000000000000000001,E = 152,M = 2-23,最终表示的结果为225 + 4;

CAST_ROUND模式舍入得尾数00000000000000000000001,E = 152,M = 2-23,最终表示的结果为225 + 4;

CAST_TRUNC模式舍入得尾数00000000000000000000000,E = 152,M = 0,最终表示的结果为225

half

示例1:输入212 + 3,写成half的表示形式:212 *(1 + 2-11 + 2-12),要求E = 12 + 15 = 27,M = 2-11 + 2-12

由于half只有10bit尾数位,因此要进行舍入。

CAST_RINT模式舍入得尾数0000000001,E = 27,M = 2-10,最终表示的结果为212 + 4;

CAST_FLOOR模式舍入得尾数0000000000,E = 27,M = 0,最终表示的结果为212

CAST_CEIL模式舍入得尾数0000000001,E = 27,M = 2-10,最终表示的结果为212+ 4;

CAST_ROUND模式舍入得尾数0000000001,E = 27,M =2-10,最终表示的结果为212 + 4;

CAST_TRUNC模式舍入得尾数0000000000,E = 27,M = 0,最终表示的结果为212

示例2:输入232 - 1,SAT模式返回65504.0,NO_SAT模式返回inf。

bfloat16_t

示例1:输入29 + 3,写成bfloat16_t的表示形式:29 *(1 + 2-8 + 2-9),要求E = 9 + 127 = 136,M = 2-8 + 2-9

由于bfloat16_t只有7bit尾数位,因此要进行舍入。

CAST_RINT模式舍入得尾数0000001,E = 136,M = 2-7,最终表示的结果为29 + 4;

CAST_FLOOR模式舍入得尾数0000000,E = 136,M = 0,最终表示的结果为29

CAST_CEIL模式舍入得尾数0000001,E = 136,M = 2-7,最终表示的结果为29+ 4;

CAST_ROUND模式舍入得尾数0000001,E = 136,M = 2-7,最终表示的结果为29 + 4;

CAST_TRUNC模式舍入得尾数0000000,E = 136,M = 0,最终表示的结果为29

int64_t

float

示例1:输入225 + 3,写成float的表示形式:225 * (1 + 2-24 + 2-25),要求E = 25 + 127 = 152,M = 2-24 + 2-25

由于float只有23bit尾数位,因此要进行舍入。

CAST_RINT模式舍入得尾数00000000000000000000001,E = 152,M = 2-23,最终表示的结果为225 + 4;

CAST_FLOOR模式舍入得尾数00000000000000000000000,E = 152,M = 0,最终表示的结果为225

CAST_CEIL模式舍入得尾数00000000000000000000001,E = 152,M = 2-23,最终表示的结果为225 + 4;

CAST_ROUND模式舍入得尾数00000000000000000000001,E = 152,M = 2-23,最终表示的结果为225 + 4;

CAST_TRUNC模式舍入得尾数00000000000000000000000,E = 152,M = 0,最终表示的结果为225

uint64_t

float

示例1:输入225 + 3,写成float的表示形式:225 * (1 + 2-24 + 2-25),要求E = 25 + 127 = 152,M = 2-24 + 2-25

由于float只有23bit尾数位,因此要进行舍入。

CAST_RINT模式舍入得尾数00000000000000000000001,E = 152,M = 2-23,最终表示的结果为225 + 4;

CAST_FLOOR模式舍入得尾数00000000000000000000000,E = 152,M = 0,最终表示的结果为225

CAST_CEIL模式舍入得尾数00000000000000000000001,E = 152,M = 2-23,最终表示的结果为225 + 4;

CAST_ROUND模式舍入得尾数00000000000000000000001,E = 152,M = 2-23,最终表示的结果为225 + 4;

CAST_TRUNC模式舍入得尾数00000000000000000000000,E = 152,M = 0,最终表示的结果为225