【问题标题】:Converting floats to strings in javascript在javascript中将浮点数转换为字符串
【发布时间】:2012-10-17 20:09:09
【问题描述】:

好的,我想将一个 THREE.Vector3 数组有效地保存到本地存储中。由于 javascript 使用字符串工作,我想使用最有效的比特率将 32 位浮点数转换为字符串。即理想的 32 位浮点 = 4 * 8 位,这在 C++ 之类的东西中很容易实现

问题似乎是第一个 Javascript 字符串是包含一些填充的 UTF

http://en.wikipedia.org/wiki/UTF-8

其次,我当前使用的代码 0 被转换为 '' 然后被省略,使得转换后的字节长度不可靠。

String.fromCharCode(0) == ''

var float2str = function(num)
{
    var bytestream = new Array();
    var view = new DataView(new ArrayBuffer(4));
    view.setFloat32(0,num);

    bytestream.push(view.getUint8(0));
    bytestream.push(view.getUint8(1));
    bytestream.push(view.getUint8(2));
    bytestream.push(view.getUint8(3));
    return String.fromCharCode(view.getUint8(0),view.getUint8(1),view.getUint8(2),view.getUint8(3))

}

var str2float = function(str)
{

    var bytestream = unpack(str)
    var view = new DataView(new ArrayBuffer(4));
    view.setUint8(0,bytestream[0]);
    view.setUint8(1,bytestream[1]);
    view.setUint8(2,bytestream[2]);
    view.setUint8(3,bytestream[3]);
    return view.getFloat32(0);
}

谢谢!

【问题讨论】:

  • 为什么不能简单地将浮点数存储为浮点数?我的意思是,据我所知,localStorage 应该能够有效地存储所有 JavaScript 对象,无论它们的类型如何。
  • 您到底从哪里听说过 javascript 只适用于字符串?
  • 我认为他的意思是 localStorage 仅适用于字符串。
  • 是的,我相信您必须在本地存储中存储一个字符串。如果你存储一个像 Pi - 3.142.. 这样的数字。每个数字都存储为 1 个字符,这是非常无用的

标签: javascript byte three.js chars


【解决方案1】:

诀窍在于获取可打印的无符号 8 位整数的字符串值。我发现如果您的 8 位数字太小或太大(超出 ASCII 值的“面包​​和黄油”范围),您最终会得到无法打印的东西。因此,我们可以使用浮点数中的 4 位值来使用长度为 8 的字符串,并将这些值偏移到可打印范围 (+32) 中,而不是使用浮点数的四个 ASCII 值创建长度为 4 的字符串。这是我的解决方案:

var offset = 33;

var float2str = function(num){
    var view = new DataView(new ArrayBuffer(4));
    view.setFloat32(0,num);

    var fourbits = [];
    for ( var i = 0; i < 4; i++ ){
        // split each byte into two 4-bit values
        fourbits.push(view.getUint8(0) >> 4);
        fourbits.push(view.getUint8(0) & 15);
    }

    for ( var i = 0; i < 8; i++ ){
        // build a string with offset four-bit values
        fourbits[i] = String.fromCharCode(offset+fourbits[i]);
    }
    return fourbits.join('');

};

var str2float = function(str){
    var bytestream = str;
    var view = new DataView(new ArrayBuffer(4));

    for(var i = 0; i < 4; i++){
        // re-convert the characters into bytes.
        view.setUint8(i, ((bytestream[i*2].charCodeAt() - offset) << 4) + bytestream[i*2+1].charCodeAt() - offset);
    }

    return view.getFloat32(0);
};

console.log(float2str('2.251')); // "%!\"!\"!'#"
console.log(str2float(float2str('2.251'))); // 2.250999927520752

我希望这会有所帮助。

【讨论】:

  • 我在这里使用33 作为偏移量,这样我们的输出字符串中就不会出现空格,但32 也可以。
  • 由于最初的目标是有效地打包浮点数,因此每个浮点数使用 8 个字节会失败,因为在许多实际情况下,常规字符串表示会更短。 (根据维基百科,32 位浮点数具有 6-9 位有效数字的精度,这可能转化为字符串的 11 个字节的最坏情况(添加小数点和减号),但我猜典型的数字/足够的精度可能最可能会以更少的方式实现(例如 2595e-8 = 7))。
  • 也许在本地存储中存储大量数字的最佳选择是简单地创建包含数字的 JSON 字符串 - 并在将其保存到本地存储之前对其运行 BZip。
  • 嗨 Jason,感谢您的帮助,虽然您的代码确实可以工作,但它会将 32 位到 8 个 16 位字符打包,最终为 128 位/浮点数。如果可能的话,我想把它降低到 64 位/浮点数。我曾尝试在 JSON 字符串上使用基于 LZ78 的 Zip,但即使压缩比为 10:1,它们最终仍然比必要的大得多。
【解决方案2】:

使用 base64 编码。它将一次将 6 位转换为可打印的 ASCII 字符(在 UTF-8 中也是如此)。因此,一个浮点数实际上需要 5.33 个字节(分数是可用的,即,只要将数组作为一个整体而不是单个浮点数编码,它就不是 6 个字节),但这仍然应该节省一些空间。

这是一个直接从ArrayBuffer 转换为base64 字符串的函数(不是我的):https://gist.github.com/958841

【讨论】:

    猜你喜欢
    • 2011-11-25
    • 1970-01-01
    • 2022-01-16
    • 2016-02-06
    • 2014-09-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多