我正在尝试存储一个非常大的数字,该数字大于 INTEGER 和 REAL 字段类型可以容纳的 8 个字节。我需要能够返回包含此字段中的数字的行,该数字小于或大于我指定的另一个大数字。我不知道该怎么做。似乎我唯一的选择是将其存储为 TEXT,但是当我尝试在查询中使用 > 和 < 进行比较时遇到问题,因为 TEXT 的比较与数字比较不同(当数字的位数不同)。我尝试过使用 BLOB 或将我的大数存储为字节数组,但无济于事。用零填充数字以使它们具有相同的位数也不起作用,因为我不知道数字可能有多大。任何帮助表示赞赏。谢谢!
1 回答
对于存储,您唯一的选择是 TEXT 或 BLOB,因此您必须以某种方式对数字进行编码,以便字典顺序和数字顺序相同。
对于无符号数,您可以使用类似于 SQLite4 的varint
encoding的机制:
让编码的字节被称为 A0, A1, A2, ..., A8。
如果 A0 介于 0 和 240(含)之间,则结果为 A0 的值。
如果 A0 介于 241 和 248 之间,则结果为 240+256*(A0-241)+A1。
如果 A0 为 249,则结果为 2287+256*A1+A2。
如果 A0 为 250,则结果为 A1..A3 作为 3 字节大端整数。
如果 A0 为 251,则结果为 A1..A4 作为 4 字节大端整数。
如果 A0 为 252,则结果为 A1..A5 作为 5 字节大端整数。
如果 A0 为 253,则结果为 A1..A6 作为 6 字节大端整数。
如果 A0 为 254,则结果为 A1..A7 作为 7 字节大端整数。
如果 A0 为 255,则结果为 A1..A8 作为 8 字节大端整数。
以上是为最多 64 位数字设计的。只要你有一个上限,为更大的数字扩展机制是微不足道的。
如果数字可以签名,则必须将A0
范围分成两半,并将前半部分用于负数。
如果您不需要进行计算,您可以使用相同的原则来存储 ASCII 数字而不是二进制值。也就是说,使用具有固定长度的前缀来指定数字的长度,然后是数字。假设您的号码不超过 9999 位,您可以使用四个前缀长度,例如:
0001|0 ...
0001|9
0002|10 ...
0002|99
0003|100 ...
0060|321741185926535897932384626433832795281828459045235360287471
如果这里需要负值,则必须为正确排序的负数/正数选择一个附加前缀( / 的 ASCII 顺序-
是+
错误的,所以最好使用n
/之类的东西p
),并且必须使用9999 之类的前缀 -负数的长度,以便较小的负数具有较小的前缀。