词法元素(五)
2、浮点常量
浮点常量包括十进制浮点常量(decimal-floating-constant)和十六进制浮点常量(hexadecimal-floating-constant)。浮点常量存在一个有效部分(significand part),后跟一个指数部分(可选)和一个指定浮点常量类型的后缀(可选);有效部分的组成可以包括表示整数部分(whole-number part)的数字序列,后跟小数点(.),后跟表示小数部分(fraction part)的数字序列。
十进制浮点常量的语法格式如下所示:
digit-sequenceopt . digit-sequence exponent-partopt floating-suffixopt digit-sequence . exponent-partopt floating-suffixopt digit-sequence exponent-part floating-suffixopt
其中digit-sequence是十进制数字序列,exponent-part是指数部分,floating-suffix是浮点后缀,opt表示可选。
指数部分的语法格式如下所示:
e signopt digit-sequence E signopt digit-sequence
其中sign是符号,值为+或者-;digit-sequence是十进制数字序列。
对于十进制浮点常量,如果有效部分存在小数点,指数部分是可选的;如果有效部分不存在小数点,指数部分是必须存在的。
2.56 //合法的十进制浮点常量。 3. //合法的十进制浮点常量。 .5 //合法的十进制浮点常量。 5E3 //合法的十进制浮点常量。 3.2e-3 //合法的十进制浮点常量。
十进制浮点常量的有效部分解释为十进制有理数(rational number),指数部分的数字序列解释为十进制整数。对于十进制浮点常量,指数表示10的幂。
2.3E+2 //等于230.0。 5.6E-2 //等于0.056。
十六进制浮点常量的语法格式如下所示:
prefix hex-digit-sequenceopt . hex-digit-sequence binary-exponent-part floating-suffixopt prefix hex-digit-sequence . binary-exponent-part floating-suffixopt prefix hex-digit-sequence binary-exponent-part floating-suffixopt
其中prefix是十六进制前缀,即0x或者0X,hex-digit-sequence是十六进制数字序列,binary-exponent-part是指数部分,floating-suffix是浮点后缀,opt表示可选。
指数部分的语法格式如下所示:
p signopt digit-sequence P signopt digit-sequence
其中sign是符号,值为+或者-;digit-sequence是十进制数字序列。
对于十六进制浮点常量,指数部分是必须存在的。
0X2a.2aP+5 //合法的十六进制浮点常量。 0X.2aP+5 //合法的十六进制浮点常量。 0X2.P2 //合法的十六进制浮点常量。 0X3P2 //合法的十六进制浮点常量。
十六进制浮点常量的有效部分解释为十六进制有理数(rational number),指数部分的数字序列解释为十进制整数。对于十六进制浮点常量,指数表示2的幂。
0X2a.2aP+5 //等于1349.250000。 0X.2aP+5 //等于5.250000。 0X2.P2 //等于8.000000。 0X3P2 //等于12.000000。
对于十进制浮点常量以及十六进制浮点常量,如果FLT_RADIX不是2的幂,结果要么是最接近的可表示值,要么是紧邻最接近可表示值的较大或者较小的可表示值,具体由实现定义。对于十六进制浮点常量,如果FLT_RADIX是2的幂,结果将正确舍入。
浮点常量后缀及其对应类型如下表所示:
| 后缀 | 类型 |
| 无后缀 | double |
| f或者F | float |
| l或者L | long double |
| df或者DF | _Decimal32 |
| dd或者DD | _Decimal64 |
| dl或者DL | _Decimal128 |
浮点后缀df、dd、dl、DF、DD和DL不能用于十六进制浮点常量。
无后缀浮点常量的类型是double类型;如果后缀是f或者F,浮点常量的类型是float类型;如果后缀是l或者L,浮点常量的类型是long double类型;如果后缀是df或者DF,浮点常量的类型是_Decimal32类型;如果后缀是dd或者DD,浮点常量的类型是_Decimal64类型;如果后缀是dl或者DL,浮点常量的类型是_Decimal128类型。
0X1.2P-3F //float类型。 0X2.3P2 //double类型。 0X2.P-4L //long double类型。 4.5E+3DF //_Decimal32类型。 1.23DD //_Decimal64类型。 1.3E-3DL //_Decimal128类型。
ISO/IEC 9899:2024标准允许在浮点常量中使用数字分隔符,但目前仅限于十进制浮点常量;数字分隔符仅用于分隔数字,在确定浮点常量值时数字分隔符会被忽略。
3.14'159 //等于3.14159。
浮点常量值的表示范围和精度可以大于后缀对应类型所要求的范围和精度;当宏FLT_EVAL_METHOD值为1时,将按double类型的范围和精度评估float类型浮点常量;当宏FLT_EVAL_METHOD值为2时,将按long double类型的范围和精度评估float类型和double类型浮点常量;但浮点常量的类型不会因此改变。
十六进制浮点常量可用于获取语义类型(semantic type)的精确值,这些值与评估格式(evaluation format)无关。强制类型转换会生成语义类型值,但取决于舍入模式(rounding mode),并可能引发不精确浮点异常(inexact floating-point exception)。
浮点常量编译时转换成内部格式。浮点常量的转换不应在程序执行时引发异常条件或者浮点异常。所有相同源形式的浮点常量应转换成相同内部格式;如果编译时舍入方向相同,应转换成相同值。3.14、3.140、314e-2、314e-02和3.14L具有不同的源形式,因此可以转换成不同的内部格式和值;尽管它们可以使用相同的内部格式和值。
如果一个十六进制浮点常量不能准确地以其评估格式(evaluation format)表示,实现应发出一条诊断信息;然后再继续编译程序。
编译时浮点常量的转换应与执行时库函数(例如:strtod函数。)对字符串的转换相匹配,前提是两种转换都适合匹配的输入、相同的结果格式(result form)和默认的执行时舍入(default execution-time rounding)。
浮点常量本身不包含符号,其算术负值将浮点常量舍入后的值用作一元负号运算符(-)的操作数生成;不同的是数值转换函数(例如:strtod、strtof等函数。)可以将符号作为输入值的一部分,并对算术取反的输入值进行转换和舍入。
浮点常量舍入前取反与舍入后取反可能导致不同结果,这与舍入方向及结果是否正确舍入有关;例如:当两者使用就近舍入或者向0舍入能够正确舍入时,结果相同;使用向上舍入或者向下舍入,当两者是不精确值,并且正确舍入,结果不同。
生成精确结果的转换不受取反和舍入顺序的影响。对于基数是10的类型,十进制浮点常量在其评估格式表示的精度和范围内可以精确转换。对于基数是2的幂的类型,十六进制浮点常量在其评估格式表示的精度和范围内可以精确转换。
2.1、十进制浮点类型的浮点常量
十进制浮点类型是ISO/IEC 9899:2024标准新增内容,包括_Decimal32、_Decimal64、_Decimal128三种类型。
对于浮点数x,
可以使用整数三元组(s, c, q)表示;其中s是符号;c是去掉小数点后的数字序列值;存在指数部分的情况下,q等于指数值减去小数点后的位数;不存在指数部分的情况下,q等于0减去小数点后的位数。
0.DD //(+1, 0, 0) 0.0DD //(+1, 0, -1) 0.E3DD //(+1, 0, 3) 10.DD //(+1, 10, 0) 0.1DD //(+1, 1, -1) 1.23E2DD //(+1, 123, 0) 123.DD //(+1, 123, 0) 1.23E-2DD //(+1, 123, -4)
值相同、指数不同的十进制浮点类型的浮点常量具有不同的内部表示。
精度值以及q在不同十进制浮点类型中的取值范围如下表所示:
| 类型 | _Decimal32 | _Decimal64 | _Decimal128 |
| 精度值(位数) | 7 | 16 | 34 |
| 最大值(qmax) | 90 | 369 | 6111 |
| 最小值(qmin) | -101 | -398 | -6176 |
由于结果类型的精度或者范围不足而需要舍入时,c将舍入到结果类型允许的全精度(full precision),并在结果类型允许的范围内调整q,前提是舍入不会生成无穷大。如果类型的全精度要求q小于类型的最小值,那么q将为最小值,并且c在次规格范围(subnormal range)内进行相应调整,可能会调整为0。
在就近舍入以及_Decimal64类型浮点常量按_Decimal64类型的范围和精度评估的情况下,以下是一些_Decimal64类型浮动常量及其对应的整数三元组。
98765432109876543210.DD //(+1, 9876543210987654, 4) 987654E-400DD //(+1, 9876, -398) 9876E-402DD //(+1, 0, -398)