简介
类型转换分为隐式转换和显式转换。隐式转换由系统在类型不匹配时自动执行。
显式转换通过调用类型转换API主动完成,API将输入数据从源类型转换为目标类型,并返回转换结果。
转换过程遵循规定的处理规则。类型转换的结果受舍入模式和饱和模式的影响。浮点数的表示方式和舍入规则请见类型转换。
隐式转换
隐式转换是指在不显式指定目标类型的情况下,系统自动将数据从源类型转换为目标类型的行为。
1 2 | int32_t a; a = 2.2f; // a = 2 |
输入数据类型 |
输出数据类型 |
舍入规则与特殊值说明 |
||
|---|---|---|---|---|
整型 |
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。 宽范围数据转成窄范围数据时:
|
half |
int32_t/uint32_t |
|||
bfloat16_t |
int32_t/uint32_t |
|||
整型 |
int32_t |
浮点型变量 |
float/half/bfloat16_t |
舍入规则遵循CAST_RINT。 宽范围数据转成窄范围数据时:
|
uint32_t |
float/half/bfloat16_t |
|||
int64_t |
float |
|||
uint64_t |
float |
|||
浮点型变量 |
float |
浮点型变量 |
half/bfloat16_t |
舍入规则遵循CAST_RINT。 宽范围数据转成窄范围数据时:
|
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类型能表示的范围 |
舍入模式
舍入模式控制转换过程中精度损失的处理方式。
舍入模式 |
描述 |
接口名格式 |
|---|---|---|
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特殊值以及转换后超出目标类型范围结果的处理方式。
模式 |
描述 |
接口名格式 |
|---|---|---|
非饱和模式 |
默认模式。
|
srctype2dsttype_r[xx] |
饱和模式 |
饱和模式下:
|
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时,接口转换结果为饱和模式。
对如下两种情况,饱和行为只受ctrl[48]控制。
- 窄范围数据转换为宽范围数据,且转换的目的操作数类型不是float,即half转bfloat16_t、hifloat8_t转half。
- half转half、bfloat16_t转bfloat16_t。
具体行为如下:
- 当CTRL[48] = 1时,接口转换结果为非饱和模式。
- 当CTRL[48] = 0时,接口转换结果为饱和模式。
对于转换的目标类型为float的情况,所有类型转换接口只支持非饱和模式。浮点数转换为整数时,转换结果均采用饱和模式。
数据类型转换规则示例
输入数据类型 |
输出数据类型 |
精度转换规则示例 |
|---|---|---|
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 。 |