TON 智能合约中的算术运算始终使用整数,从不使用浮点数,因为浮点数是不可预测的。 因此,重点应放在整数及其处理上。
Int
是一个 257 位的有符号整数类型。
它能够存储 −2256 和 2256−1 之间的整数。
符号
Tact 支持以各种方式将 Int
的基元值写成 整数字面量。
大多数符号允许在数字之间添加下划线 (_
),但下列符号除外:
- 字符串表示法,如 纳吨 案例所示。
- 带前导零的十进制数 0。一般不鼓励使用,参见 下文。
此外,不允许在 4__2 中连续使用多个下划线,或在 42_ 中使用尾部下划线。
十进制
最常见、最常用的数字表示方法,使用十进制数字系统: 123456789。
您可以使用下划线(_
)来提高可读性: 123_456_789 等于 123456789。
十六进制
使用十六进制数字系统表示数字,用 0x(或 0X)前缀表示:0xFFFFFFFFF。
使用下划线(_
)提高可读性:0xFFF_FFFF_FFF 等于 0xFFFFFFFFF。
八进制
使用八进制数字系统表示数字,用 0o(或 0O)前缀表示:0o777777777。
使用下划线(_
)提高可读性:0o777_777_777 等于 0o777777777。
二进制
使用二进制数字系统表示数字,用 0b(或 0B)前缀表示:0b111111111。
使用下划线(_
)提高可读性:0b111_111_111 等于 0b111111111。
NanoToncoin
美元的算术运算需要在圆点后保留两位小数,这两位小数用于美分的计算。但是,如果我们只能用整数来表示数字 $1.25,我们该如何表示呢?解决的办法是直接使用 cents。这样,$1.25 就变成了 125 美分。我们只需记住最右边的两位数代表小数点后的数字。
同样,在使用 TON 区块链的主要货币 Toncoin 时,需要九位小数,而不是两位小数。可以说,纳米通币是通币的 1091。
因此,1.25 Toncoin 的数量,可以用 Tact 表示为 ton("1.25")
,实际上就是数字 1250000000。我们把这些数字称为 纳米吨币(或 纳米吨),而不是 美分。
序列化
将 Int
值编码为持久状态(contracts 和 traits 的字段)时,通常最好使用比 257-bits 更小的表示形式,以降低存储成本。 这些表示法的使用也被称为 “序列化”,因为它们代表了 TON 区块链运行的本地TL-B类型。
持久状态大小在状态变量的每个声明中都会在 as
关键字后指定:
整数序列化也适用于 [Structs](/book/structs and-messages#structs) 和 [Messages](/book/structs and-messages#messages) 的字段,以及 maps 的键/值类型:
动机很简单:
- 在州成本中存储 1000 257- 位整数每年约需 0.184 ton 。
- 相比之下,存储 1000 32-bit 整数每年只需花费 0.023 ton 。
序列化类型
名称 | TL-B | 包容性范围 | 占用空间 |
---|
uint8 | [uint8 ][tlb-构建] | 0 到 28−1 | 8 位 = 1 字节 |
uint16 | uint16 | 0 到 216−1 | 16 位 = 2 字节 |
uint32 | uint32 | 0 到 232−1 | 32 位 = 4 字节 |
uint64 | uint64 | 0 到 264−1 | 64 位 = 8 字节 |
uint128 | uint128 | 0 到 2128−1 | 128 位 = 16 字节 |
uint256 | uint256 | 0 到 2256−1 | 256 位 = 32 字节 |
int8 | [int8 ][tlb-构建] | −27 至 27−1 | 8 位 = 1 字节 |
int16 | int16 | −215 至 215−1 | 16 位 = 2 字节 |
int32 | int32 | −231 至 231−1 | 32 位 = 4 字节 |
int64 | int64 | −263 至 263−1 | 64 位 = 8 字节 |
int128 | int128 | −2127 至 2127−1 | 128 位 = 16 字节 |
int256 | int256 | −2255 至 2255−1 | 256 位 = 32 字节 |
int257 | int257 | −2256 至 2256−1 | 257 位 = 32 字节 + 1 位 |
coins | [VarUInteger 16 ][varuint] | 0 到 2120−1 | 4 和 124 位之间,见下文 |
变量 coins
类型
在 Tact 中,coins
是TL-B表示法中[VarUInteger 16
][varuint]的别名,即根据存储给定整数所需的最佳字节数,它的位长是可变的,通常用于存储nanoToncoin金额。
这种序列化格式包括两个 TL-B 字段:
- len”,一个 4位无符号大二进制整数,存储所提供值的字节长度
- value”,即所提供值的 8 * len$ 位无符号大二进制表示法
也就是说,序列化为 coins
的整数占用 4 至 124 位(len
为4 位,value
为 0 至 15 字节),其值范围为 0 至 2120−1 之间。
例如
业务
所有数字的运行时计算都是在 257 位完成的,因此 溢出 非常罕见。 不过,如果任何数学运算出现溢出,就会抛出异常,事务也会失败。 可以说,Tact 的数学默认是安全的。
请注意,在同一计算中混合使用 [不同状态大小](#序列化)的变量是没有问题的。 在运行时,无论如何,它们都是相同的类型 - 257-比特签名,因此不会发生溢出。
不过,这仍可能导致在事务的计算阶段出现***错误。 请看下面的例子:
这里,“oneByte” 被序列化为 uint8
,只占用一个字节,范围从 0 到 28−1,即 255。在运行时计算中使用时,不会发生溢出,所有计算结果都是 257 位有符号整数。但是,就在我们决定将 tmp
的值存储回 oneByte
的那一刻,我们收到了一个错误,退出代码 5,错误信息如下:整数超出预期范围。