0

据说

javascript 中的所有数字都是 64 位浮点数。

我想知道数字是否总是在内存中使用 64 位?

我有这样的数据结构(在 C 风格的代码中)

{
  int x; // [0-9]
  int y; // [0-9]
  int d; // [0-3]
}

x 和 y 将绝对在 [0-9] 的范围内,并且 d 的唯一可能值是 0、1、2、3。

如果我将它们存储为 3 个分隔数字,该结构会使用 64 位 * 3 = 192 位 = 24 字节吗?

如果是这样,我想将它存储在一个数字中,x * 100 + y * 10 + d,这应该只使用 64 位(8 字节)。在不考虑 CPU 使用率的情况下这是否更好。

我还考虑了字符串解决方案。

x.toString() + y.toString() + d.toString();

因为所有的 x、y 和 d 都小于 10,所以它们应该只有 1 个字符,16 位。所以结构变成 16 bits * 3 = 48 bits = 6 Bytes。这是最优化存储的解决方案吗?

那么mongoDB中的存储呢?如果我将数据结构存储到mongoDB中,是不是同样的情况?


我写了一个片段来测试 mongo 中的存储。最终结构包括上述结构的 3 个实例。总量为66816。

我将它们存储到 3 个独立的数据库中:

  • 布局完整(我丢失了一个's'):一个数组包括 3 {x: valueX, y: valueY, d: valueD}
  • layouts-int: xydxydxyd (十进制) ex. 233250750 表示 {x:2,y:3,d:3},{x:2,y:5,d:0},{x:7,y:5,d:0}
  • layouts-str:将上面的 int 转换为 2-char 字符串。String.fromCharCode(i >> 16) + String.fromCharCode(i & 0xFFFF)

结果是……

> show dbs
layout-full     0.03125GB
layouts-int     0.03125GB
layouts-str     0.03125GB

但细节是...

布局完整的集合

"size" : 8017920,
"avgObjSize" : 120,
"storageSize" : 11182080,

layouts-int 中的集合

"size" : 2138112,
"avgObjSize" : 32,
"storageSize" : 5591040,

layouts-str 中的集合

"size" : 2405396,
"avgObjSize" : 36.000299329501914,
"storageSize" : 5591040,

从这些结果中,我发现 int 存储是最节省空间的方法。

我也这样做了:

> db.tiny.save({})
> db.tiny.stats().avgObjSize
24
> db.tiny.remove()
> db.tiny.save({l:null})
> db.tiny.stats().avgObjSize
28
> db.tiny.remove()
> db.tiny.save({l:[{x:null,y:null,d:null},{x:null,y:null,d:null},{x:null,y:null,d:null}]})
> db.tiny.stats().avgObjSize
84

所以_id将使用 24 个字节,而关键部分 ,{l:将使用 4 = 28 - 24 个字节。

而且你会发现一个整数使用 32 - 28 = 4 个字节,所以小于 2^31 的整数似乎在 mongo db 中存储为 32 位整数。

还有 in string 解决方案,一个 2-char 字符串使用 36 - 28 = 8 个字节,正好等于我猜到的值。

而对于全结构解决方案,从上次的 tiny db 测试中,您可以看到没有数据的结构使用 84 字节,因此数据使用 120 - 84 = 36 字节 = 9 * 4 字节。我的最终数据结构中只有 9 个整数(三元组 x、y、d)。这也证明整数存储为 32 位整数。

为什么空结构使用 84 字节?

通过一些更多的实验,我发现1个数组或空json对象使用4个字节,而一个键使用* 4。

所以,空结构实际上是

{                                               // 1 object +4 bytes       = 4
  '_id': ObjectId('0123456789abcdef012345678'), // 3-char key + 12-byte id = 24
  'l': [                                        // 1-char key + 1 array    = 8
    {'x': null, 'y': null, 'd': null},          // 1 object+ 3 keys        = 16
    {'x': null, 'y': null, 'd': null},          // 1 object+ 3 keys        = 16
    {'x': null, 'y': null, 'd': null}           // 1 object+ 3 keys        = 16
  ]
}

结果是 4 + 24 + 8 + 16 * 3 = 84 字节。

我希望我的实验对其他人有用。

4

1 回答 1

1

这会将三个数字存储在一个字符串中。做得更好的唯一方法是使用类型化数组,但我不确定这是否是一个选项。

function showMeSomeMagic(x, y, d) {
  // we assume that:
  // - x, y are integers in the range [0 9] 
  // - d is an integer in the range [0 3]
  // if not add the appropriate checks/casting/coercing
  var n = (d << 8) + (y << 4) + x;
  // return a String made of a single Unicode code point in 
  // the range [0xE000 0xE399], i.e. inside the Unicode BMP PUA
  return String.fromCharCode( n + 0xE000 );
}

function showMeSomeInverseMagic(s) {
  // we assume that:
  // s is a String created by showMeSomeMagic
  var n = s.charCodeAt(0) - 0xE000;
  var x = n & 15;
  var y = (n >> 4) & 15;
  var d = (n >> 8) & 15;
  return { x:x, y:y, d:d };
}

编辑:根据OP评论更新

于 2012-05-18T08:15:12.693 回答