数值类型(int->(enum,bool),float)
1 概述
本章节介绍GS语言中的数值类型,包括整型(int)、布尔型(bool)、枚举(enum)和浮点型(float),涵盖取值范围、运算规则、类型转换及特殊值处理等核心内容。
本章内容适用于 GS 初学者快速学习或回顾 GS 数值类型相关内容。
通过阅读本文档,您将了解 GS 中数值类型的取值范围、运算规则、类型转换及溢出处理等内容。
2 int 整型
整型用于表示整数,即没有小数部分的数字。它在 GS 中以补码形式存储,这使得它能高效地表示正数、负数和零,并方便进行算术运算。
-
在 GS 中整型变量以类型
int声明,且为64位的有符号整数。 -
在声明了整型变量且未初始化时整型变量的默认值为0.
2.1 int 声明
在声明整型变量且没有为整型变量赋予初始值的情况下,整型变量的默认值为0。整型的声明、初始化、默认值的形式如下:
// 声明和初始化
int age = 25;
int temp;
writeln(age);
writeln(temp);
示例 2-1:整型的声明初始化及默认值
输出结果如下:
25
0
2.2 int 取值范围
GS 中int整型的取值范围为 -9223372036854775808(-2^63) 到 9223372036854775807(2^63 - 1),超出范围的运算会导致溢出(Overflow),产生未定义行为或错误结果。溢出示例:
int max_val = 9223372036854775807; // int 的最大值 (2^63 - 1)
int min_val = -9223372036854775808; // int 的最小值 (-2^63)
writeln("初始值:");
writeln("max_val = ", max_val);
writeln("min_val = ", min_val);
// 溢出示例 1: 最大值加 1
writeln("\n1. 最大值加 1 (max_val + 1):");
int result1 = max_val + 1;
writeln("结果: ", result1);
writeln("解释: 从最大值溢出,变成了最小值");
// 溢出示例 2: 最小值减 1
writeln("\n2. 最小值减 1 (min_val - 1):");
int result2 = min_val - 1;
writeln("结果: ", result2);
writeln("解释: 从最小值溢出,变成 了最大值");
// 溢出示例 3: 乘法溢出
writeln("\n3. 大数乘法 (max_val * 2):");
int result3 = max_val * 2;
writeln("结果: ", result3);
writeln("解释: 乘法运算结果超出范围,发生截断");
// 溢出示例 4: 溢出传播
writeln("\n4. 溢出传播 (max_val + 1 - 1):");
int result4 = max_val + 1 - 1;
writeln("结果: ", result4);
writeln("解释: 溢出后继续运算,结果不符合数学逻辑");
示例2-2:整型计算溢出
输出结果如下:
初始值:
max_val = 9223372036854775807
min_val = -9223372036854775808
1. 最大值加 1 (max_val + 1):
结果: -9223372036854775808
解释: 从最大值溢出,变成了最小值
2. 最小值减 1 (min_val - 1):
结果: 9223372036854775807
解释: 从最小值溢出,变成了最大值
3. 大数乘法 (max_val * 2):
结果: -2
解释: 乘法运算结果超出范围,发生截断
4. 溢出传播 (max_val + 1 - 1):
结果: 9223372036854775807
解释: 溢出后继续运算,结果不符合数学逻辑
2.3 int 字面量支持
GS int 整型支持十进制、二进制、八进制、十六进制和字符形式的字面量,如下所示:
int val;
writeln(val); // 整型的默认值为 0
val = 65; // 四个式子等价,val的值都是18
writeln(val);
val = 0b1000001; // 二进制使用 0b 开头
writeln(val);
val = 0101; // 八进制使用 0 开头
writeln(val);
val = 0x41; // 十六进制使用 0x 开头
writeln(val);
val = 'A'; // 字符形式,val的值是65
writeln(val);
示例2-3:整型字面量支持
输出结果如下
65
65
65
65
65
2.4 基础运算
整型可以进行 +、-、*、/、% 等基础运算操作,示例如下
int a = 10, b = 3;
writeln(a + b); // 13
writeln(a - b); // 7
writeln(a * b); // 30
writeln(a / b); // 3(整数除法)
writeln(a % b); // 1(取模)
示例2-4:int基本数学运算示例
输出结果如下:
13
7
30
3
1
2.5 类型转换
需要注意的是当整型int与浮点型float进行运算时,运算结果会被隐式类型转换为float类型,如下:
int int_val = 8;
float float_val = 6.6;
write((int_val + float_val).type_name());
示例2-5:整型与浮点型运算隐式类型转换
输出结果如下:
float
2.6 bool 与 enum
在 GS 中 enum 与 bool 类型均是整型 int 的子类型,而 bool 类型实际是 GS 内置声明的枚举enum类型。
2.6.1 bool 类型
bool 类型仅包含 true 和 false 两个值,更多用于条件判断语句中,在bool变量声明但未初始化时bool变量的默认值为 false,其声明、初始化、默认值如下:
bool flag; // flag = false
writeln(flag);
flag = true; // flag = true
writeln(flag);
示例2-6:bool 的简单使用
示例的输出结果如下:
false
true
2.6.1.1 与整型的转换
需要注意的是bool 是 int类型的子类型, 直接用bool 值向int类型变量赋值的操作是被禁止的,如下:
bool flag = 1; // true
int num = flag; // 1
writeln(0 == false); // true
示例2-7:禁止的类型转换
输出的报错如下:
Assign type mismatched, expected 'bool' got 'int'.
2.6.2 enum 类型
enum 是枚举类型,是int的子类型,主要是将相同类别不同特征的一类东西放在一起,方便取值调用。
enum 表的类型名称是map,其功能与map有点类似(key是特征名,val是int类型数值,默认从0递增),用法与C类似。enum的基本语法格式如下:
// 无描述enum
enum NO_MEMO_ENUM
{
VALUE1 = 1,
VALUE2 = 2,
VALUE3 = 3,
}
// 有描述enum
enum WITH_MEMO_ENUM
{
VALUE1 = 1:"This is enum item memo",
VALUE2 = 2:"Use after ':' symbol",
VALUE3 = 3:"Must be const string",
}
// 使用 enum 成员
writeln(NO_MEMO_ENUM.VALUE1);
writeln(NO_MEMO_ENUM.VALUE2);
示例2-8:enum 的定义与使用示例
输出的结果如下:
NO_MEMO_ENUM.VALUE1(1) @ /test/test.gs
NO_MEMO_ENUM.VALUE2(2) @ /test/test.gs
需要注意以下几点:
-
enum_name是enum的名称,必须是一个合法的标识符 -
valueN是枚举项,也应当是一个合法的标识符,通常使用大写蛇形命名法,以便于区分。 -
constantN是枚举项的值,如果不指定,则为上一个枚举项的值加1。如果是首个枚举项,则为0。 -
enum_memo_str是枚举项的描述,通常是字符串类型的常量,可以不指定。
2.6.2.1 enum 信息表
enum 类型都有对应的信息表,定义的枚举类型名称本身就是此常量表。可以通过此常量表获取枚举的相关信息:
enum AAA
{
aaa = 1:"aaa",
bbb = 2,
ccc = 3,
}
write(AAA);
示例2-9:enum 信息表示例
示例的输出结果如下:
{ /* sizeof() == 5 */
"__reverse_enum_map__" : { /* sizeof() == 3 */
1 : "aaa",
2 : "bbb",
3 : "ccc",
},
"__memo__" : { /* sizeof() == 1 */
AAA.aaa(1) @ /test/test.gs : "aaa",
},
"aaa" : AAA.aaa(1) @ /test/test.gs,
"bbb" : AAA.bbb(2) @ /test/test.gs,
"ccc" : AAA.ccc(3) @ /test/test.gs,
}
2.6.2.2 enum取值规则
enum枚举中的标识符默认从 0 开始赋值,后续依次递增 1。你可以为某个枚举符显式指定一个整数值,其后未显式赋值的枚举符会在此基础上继续递增 1。
举个一般的enum例子:
enum State
{
ZERO,
IDLE = 10,
RUN,
WAIT = 35,
EAT,
DRINK,
};
write(State);
示例2-10:enum取值规则示例
{ /* sizeof() == 8 */
"__reverse_enum_map__" : { /* sizeof() == 6 */
0 : "ZERO",
10 : "IDLE",
11 : "RUN",
35 : "WAIT",
36 : "EAT",
37 : "DRINK",
},
"__memo__" : { },
"ZERO" : State.ZERO(0) @ /test/test.gs,
"IDLE" : State.IDLE(10) @ /test/test.gs,
"RUN" : State.RUN(11) @ /test/test.gs,
"WAIT" : State.WAIT(35) @ /test/test.gs,
"EAT" : State.EAT(36) @ /test/test.gs,
"DRINK" : State.DRINK(37) @ /test/test.gs,
}
2.6.2.3 enum描述
enum 可以 带有描述信息,语法是在enum item 后紧跟冒号与对应描述的常量字符串,带有注释enum的示例如下:
enum AAA
{
aaa = 1:"aaa",
bbb = 2:"bbb",
ccc:"ccc",
}
write(AAA);
示例2-11:enum描述示例
此时输出如下:
{ /* sizeof() == 5 */
"__reverse_enum_map__" : { /* sizeof() == 3 */
1 : "aaa",
2 : "bbb",
3 : "ccc",
},
"__memo__" : { /* sizeof() == 3 */
AAA.aaa(1) @ /test/test.gs : "aaa",
AAA.bbb(2) @ /test/test.gs : "bbb",
AAA.ccc(3) @ /test/test.gs : "ccc",
},
"aaa" : AAA.aaa(1) @ /test/test.gs,
"bbb" : AAA.bbb(2) @ /test/test.gs,
"ccc" : AAA.ccc(3) @ /test/test.gs,
}
3 float 浮点型
float类型用于表示实数,即包含小数部分的数字,或非常大、非常小的数值。它通过符号位、指数和尾数来近似表示实数,表示方法可以覆盖很广的数值返回,但可能存在精度损失。在 GS 中float 是一个64位(8字节)的双精度浮点数。
3.1 float 声明
在声明浮点变量且没有为浮点变量赋予初始值的情况下,浮点变量的默认值为0.0,浮点的声明、初始化、默认值的形式如下:
float num;
writeln(num);
float num1 = 1.1;
writeln(num);
示例3-1:浮点的声明、初始化与默认值
输出的结果如下:
0.0
0.0
3.2 float 取值范围
在 GS 中 float 是一个64位(8字节)的双精度浮点数,float类型变量的近似值取值范围大约为 -1.7 × 10³⁰⁸ 到 +1.7 × 10³⁰⁸,能够提供约15-16位十进制数字的精度。
3.3 float 的基本运算
float类型支持所有的基本数学运算,示例如下:
float a = 10.5;
float b = 3.2;
float sum = a + b; // 加法
float difference = a - b; // 减法
float product = a * b; // 乘法
float quotient = a / b; // 除法
printf("Sum: %.2f\n", sum);
printf("Difference: %.2f\n", difference);
printf("Product: %.2f\n", product);
printf("Quotient: %.2f\n", quotient);
示例3-2:float 基本数学运算示例
输出结果如下:
Sum: 13.70
Difference: 7.30
Product: 33.60
Quotient: 3.28
3.4 float 字面量支持
在 GS 中 float类型的变量只支持十进制形式的字面量,其用法如下
float pi = 3.14;
float a = 3f;
float b = 3.f;
float c = 3.0f;
float d = .1f;
示例3-4:float 字面量支持示例
注意:任意两个类型之间的转换都需要强制类型转换。
int val = 3.14; // 错误
int val = (int)3.14; // 正确
float pi = 3; // 错误
float pi = 3f; // 正确
float pi = (float)3; // 正确
3.5 float 精度问题与比较操作
由于二进制表示的限制,许多常见的十进制小数(如 0.1)无法在二进制中被精确表示,就像1/3无法用十进制小数精确表示一样。这会导致微小的舍入误差。一个错误的浮点比较示例如下:
float a = 0.1;
float b = 0.2;
float c = a + b;
printf("0.1 + 0.2 = %.20f\n", c);
// 可能输出:0.1 + 0.2 = 0.30000000000000004441
if (c == 0.3)
{
printf("Equal.\n"); // 避免使用 == 直接比较!
}
else
{
printf("Not equal! See?\n"); // 通常会进入这里
}
示例3-5:错误的浮点比较示例
输出的结果如下:
0.1 + 0.2 = 0.30000000000000004441
Not equal! See?
可以看到由于微小的舍入误差 0.1 + 0.2 != 0.3,在进行浮点数比较时正确的做法是应使用一个极小的容差值来判断两个浮点数是否足够接近:
import gs.lang.math;
float c = 0.1 + 0.2;
float epsilon = 1e-10; // 根据精度需求设定容差
if (math.abs(c - 0.3) < epsilon)
{
printf("They are considered equal for practical purposes.\n");
}
示例3-6:正确的浮点比较示例
输出结果如下:
They are considered equal for practical purposes.
3.6 float 溢出问题
尽管 GS 中 float 为64位浮点数,支持的数值范围很大,但它仍有极限。进行超出范围的运算可能导致上溢或下溢。
-
上溢:当结果超出
float能表示的最大正值时,会得到特殊值 inf(正无穷)或 -inf(负无穷) -
下溢:当结果无限趋近于零,小于能表示的最小正值时,可能会得到0.0。
浮点溢出的示例如下:
float huge = 1e308;
float tooHuge = huge * 10;
printf("Infinity: %f\n", tooHuge); // 输出 inf
float tiny = 1e-320; // 可能小于最小正规范数
printf("Tiny: %O\n", tiny); // 输出 0.000000e+00
示例3-7:浮点溢出示例
输出结果如下:
Infinity: inf
Tiny: 0.0
除此之外一些数学上非法的浮点运算会得到 nan (not a number)结果,nan的产生情概况基本分成以下三类:
- 浮点数除法的 0.0 / 0.0 ,无论正负,两个数中有一个为浮点数
- 无意义的数学操作函数,如math.acos(-2) , math.sin(-2), math.log(-2) 等
- 部分 inf 运算, 如 inf - inf , inf / inf, 0 * inf
inf:infinite,表示“无穷大”。+inf 大于任何数字(除了它自己和nan), -inf小于任何数字(除了它自己和nan) , +inf 与 -inf 互为负数(但 -inf / inf 结果为 nan ) ,得到inf是需要查看是否有溢出或者除以0的情况。
inf的产生情况大致也是三类:
-
浮点数除法 1.0 /0.0 , 即非零数字除以0,两个数中有一个为浮点数
-
部分数学操作函数产生,如 log(0)
-
部分 inf 运算, 如 0 + inf inf -(-inf) -inf - inf等
以下为产生 nan 与 inf 的部分样例:
//nan 产生的部分情况如下:
math.sqrt(-1) //1. 对负数的开方,无意义
math.log(-1) //2. 对负数求对数,无意义
0.0/0.0 //3. 0 / 0 其中一个为浮点数 (保证为浮点数除法)
0.0 * (1.0 / 0.0) //4. 实际是 0 * inf
(1.0 / 0.0) / (1.0 / 0.0) //5. 实际是 inf / inf (无论正负)
(1.0 / 0.0) - (1.0 / 0.0) //6. 实际是 inf - inf
// inf 产生的部分情况如下:
1.0 / 0.0 //1. 非零数字除以0 其中一个为浮点 数(保证为浮点数除发) 得到 inf
-1.0 / 0.0 //2. 非零数字除以0 其中一个为浮点数(保证为浮点数除发) 得到 -inf
-100 + (1.0 / 0.0) //3. 实际是 -100 + inf,非nan数字加减inf
math.log(0) //4. log(0) 得到 -inf
1.0/0.0 - -1.0/0.0 //5, 实际是 inf - (-inf) 得到 inf
-1.0/0.0 - 1.0/0.0 //5, 实际是 (-inf) - inf 得到 -inf
示例 3-8:nan 及 inf 产生示例
可以自行添加输出函数,查看样例相应浮点计算的输出结果。
判断 inf 或者 nan 可以调用 math.isinf(float_number) math.isnan(float_number)
4 总结
恭喜您完成了GS语言数值类型的学习!通过本章节,您已经掌握了int(bool、enum)和float数值类型的核心知识,包括它们的取值范围、运算规则、类型转换及特殊值处理等重要内容。接下来让我们继续学习GS中的串类型,这将让您能够处理更丰富的数据形式和更复杂的应用场景。