如何在Javascript中将浮点数转换为二进制表示形式(IEEE 754)?

如何在Javascript中将浮点数转换为二进制表示形式(IEEE 754)?,javascript,binary,floating-point,ieee-754,Javascript,Binary,Floating Point,Ieee 754,在Javascript中将浮点数转换为二进制表示的最简单方法是什么?(例如,1.0->0x3F800000) 我尝试过手动操作,这在某种程度上是可行的(使用普通数字),但对于非常大或非常小的数字(无范围检查)和特殊情况(NaN、无穷大等)都失败了: 函数floatTonNumber(flt) { 变量符号=(flt=1)-0&&--floatPart; } i=-1; 而(++i=-126&&exp=0){ (bin[j]=!bin[j]-0)和&(四舍五入=0); } } i=i-2

在Javascript中将浮点数转换为二进制表示的最简单方法是什么?(例如,1.0->0x3F800000)

我尝试过手动操作,这在某种程度上是可行的(使用普通数字),但对于非常大或非常小的数字(无范围检查)和特殊情况(NaN、无穷大等)都失败了:

函数floatTonNumber(flt)
{
变量符号=(flt<0)?1:0;
flt=数学abs(flt);
var指数=数学层(数学日志(flt)/数学层LN2);
var尾数=flt/Math.pow(2,指数);

return(符号这里有一个函数,它适用于我测试过的所有东西,只是它不区分-0.0和+0.0

它基于中的代码,但专门用于32位浮点运算,并返回整数而不是字符串。我还对其进行了修改,使其更快(稍微)更可读

// Based on code from Jonas Raoni Soares Silva
// http://jsfromhell.com/classes/binary-parser
function encodeFloat(number) {
    var n = +number,
        status = (n !== n) || n == -Infinity || n == +Infinity ? n : 0,
        exp = 0,
        len = 281, // 2 * 127 + 1 + 23 + 3,
        bin = new Array(len),
        signal = (n = status !== 0 ? 0 : n) < 0,
        n = Math.abs(n),
        intPart = Math.floor(n),
        floatPart = n - intPart,
        i, lastBit, rounded, j, exponent;

    if (status !== 0) {
        if (n !== n) {
            return 0x7fc00000;
        }
        if (n === Infinity) {
            return 0x7f800000;
        }
        if (n === -Infinity) {
            return 0xff800000
        }
    }

    i = len;
    while (i) {
        bin[--i] = 0;
    }

    i = 129;
    while (intPart && i) {
        bin[--i] = intPart % 2;
        intPart = Math.floor(intPart / 2);
    }

    i = 128;
    while (floatPart > 0 && i) {
        (bin[++i] = ((floatPart *= 2) >= 1) - 0) && --floatPart;
    }

    i = -1;
    while (++i < len && !bin[i]);

    if (bin[(lastBit = 22 + (i = (exp = 128 - i) >= -126 && exp <= 127 ? i + 1 : 128 - (exp = -127))) + 1]) {
        if (!(rounded = bin[lastBit])) {
            j = lastBit + 2;
            while (!rounded && j < len) {
                rounded = bin[j++];
            }
        }

        j = lastBit + 1;
        while (rounded && --j >= 0) {
            (bin[j] = !bin[j] - 0) && (rounded = 0);
        }
    }
    i = i - 2 < 0 ? -1 : i - 3;
    while(++i < len && !bin[i]);
    (exp = 128 - i) >= -126 && exp <= 127 ? ++i : exp < -126 && (i = 255, exp = -127);
    (intPart || status !== 0) && (exp = 128, i = 129, status == -Infinity ? signal = 1 : (status !== status) && (bin[i] = 1));

    n = Math.abs(exp + 127);
    exponent = 0;
    j = 0;
    while (j < 8) {
        exponent += (n % 2) << j;
        n >>= 1;
        j++;
    }

    var mantissa = 0;
    n = i + 23;
    for (; i < n; i++) {
        mantissa = (mantissa << 1) + bin[i];
    }
    return ((signal ? 0x80000000 : 0) + (exponent << 23) + mantissa) | 0;
}
//基于Jonas Raoni Soares Silva的代码
// http://jsfromhell.com/classes/binary-parser
函数编码浮点(数字){
变量n=+数字,
状态=(n!==n)| n==-无穷大| n==+无穷大?n:0,
exp=0,
len=281,//2*127+1+23+3,
bin=新阵列(len),
信号=(n=状态!==0?0:n)<0,
n=数学绝对值(n),
intPart=数学楼层(n),
floatPart=n-intPart,
i、 最后一位,四舍五入,j,指数;
如果(状态!==0){
如果(n!==n){
返回0x7fc00000;
}
如果(n==无穷大){
返回0x7f800000;
}
if(n==-无穷大){
返回0xff800000
}
}
i=len;
而(i){
bin[--i]=0;
}
i=129;
while(intPart&&i){
bin[--i]=intPart%2;
intPart=数学楼层(intPart/2);
}
i=128;
while(floatPart>0&&i){
(bin[++i]=((floatPart*=2)>=1)-0&&--floatPart;
}
i=-1;
而(++i=-126&&exp=0){
(bin[j]=!bin[j]-0)和&(四舍五入=0);
}
}
i=i-2<0-1:i-3;
而(++i=-126&&exp=1;
j++;
}
var尾数=0;
n=i+23;
对于(;i尾数=(尾数新技术使这一过程变得简单,而且可能更具前向兼容性。我喜欢扩展内置原型,不是每个人都喜欢。因此,请随意修改以下代码,以实现经典的过程方法:

(function() {
    function NumberToArrayBuffer() {
        // Create 1 entry long Float64 array
        return [new Float64Array([this]).buffer];
    }
    function NumberFromArrayBuffer(buffer) {
        // Off course, the buffer must be at least 8 bytes long, otherwise this is a parse error
        return new Float64Array(buffer, 0, 1)[0];
    }
    if(Number.prototype.toArrayBuffer)  {
        console.warn("Overriding existing Number.prototype.toArrayBuffer - this can mean framework conflict, new WEB API conflict or double inclusion.");
    }
    Number.prototype.toArrayBuffer = NumberToArrayBuffer;
    Number.prototype.fromArrayBuffer = NumberFromArrayBuffer;
    // Hide this methods from for-in loops
    Object.defineProperty(Number.prototype, "toArrayBuffer", {enumerable: false});
    Object.defineProperty(Number.prototype, "fromArrayBuffer", {enumerable: false});
})();
测试:
(函数(){
函数NumberToArrayBuffer(){
//创建1个条目长的浮点64数组
返回新的Float64Array([this.valueOf()]).buffer;
}
函数号缓冲区(缓冲区){
//当然,缓冲区的长度必须至少为8字节,否则这是一个解析错误
返回新的Float64Array(缓冲区,0,1)[0];
}
if(Number.prototype.toArrayBuffer){
console.warn(“覆盖现有Number.prototype.toArrayBuffer-这可能意味着框架冲突、新的WEB API冲突或双重包含”);
}
Number.prototype.toArrayBuffer=NumberToArrayBuffer;
Number.fromArrayBuffer=NumberFromArrayBuffer;
//对for in循环隐藏此方法
defineProperty(Number.prototype,“toArrayBuffer”,{enumerable:false});
defineProperty(数字,“fromArrayBuffer”,{enumerable:false});
})();
var测试_数=[0.00000001,6666,NaN,无穷大,-无穷大,0,-0];
日志(“转换符号测试:”);
每个测试单元的测试编号(
函数(num){
console.log(“,Number.fromArrayBuffer((num.toArrayBuffer());
}
);
log(“数字的单个字节:”,新的Uint8Array((666).toArrayBuffer(),0,8));

我很想知道为什么要转换为IEEE单精度表示法。Javascript数字不是通常存储为双精度(64位)量吗?对于小值(
指数<-126
),您返回的是无穷大;不知怎的,我不认为这是您想要的。(还有,-0.0最后的符号位是错误的,但这可能对您的应用程序并不重要。)马克·迪金森:我正在转换为32位IEEE,因为应用程序将生成一些值,这些值将在内存编辑器中使用(使用地址+字节格式)。“指数<-126”根据维基百科,这是正确的。指数<-127不能表示,指数=-127(即添加偏差后的0)用于零和低于正常值的数字(同样根据维基百科).关于-0.0,你是对的。有没有办法检查它是否为-0.0?与0.0的比较返回真值。关于指数:输入可以是任何有效的IEEE 754双精度值;对于当前代码,如果输入值很小,如1e-60,则输出无穷大的二进制表示形式。输出可能更合适而是0.0的表示形式,这是通过将双精度值四舍五入为单精度自然得到的。要区分0.0和-0.0,我知道的唯一方法是查看
atan2(flt,-1.0)
的结果(如果JavaScript提供copysign,那将是更好的方法)。你可以用类型化数组来实现这一点:有没有一种简单的方法可以从二进制变为浮点,或者这是一个问题,或者是一种反向算法?有没有反向算法?所以基本上是
新的Uint8Array(新的Float64Array([num])。buffer,0,8)
。但是警告是不是“”只参考不相关的位模式?或者它也允许位模式改变,从而最终影响可观察值吗?@Pacerier这是一个非常好的问题,我必须做一些研究,可能会找到一个更好的解决方案,与平台无关。@Pacerier一些引擎将数据打包到不相关的位中,所以我认为caveat只是用来解释这些。如果位模式写入
// Based on code from Jonas Raoni Soares Silva
// http://jsfromhell.com/classes/binary-parser
function encodeFloat(number) {
    var n = +number,
        status = (n !== n) || n == -Infinity || n == +Infinity ? n : 0,
        exp = 0,
        len = 281, // 2 * 127 + 1 + 23 + 3,
        bin = new Array(len),
        signal = (n = status !== 0 ? 0 : n) < 0,
        n = Math.abs(n),
        intPart = Math.floor(n),
        floatPart = n - intPart,
        i, lastBit, rounded, j, exponent;

    if (status !== 0) {
        if (n !== n) {
            return 0x7fc00000;
        }
        if (n === Infinity) {
            return 0x7f800000;
        }
        if (n === -Infinity) {
            return 0xff800000
        }
    }

    i = len;
    while (i) {
        bin[--i] = 0;
    }

    i = 129;
    while (intPart && i) {
        bin[--i] = intPart % 2;
        intPart = Math.floor(intPart / 2);
    }

    i = 128;
    while (floatPart > 0 && i) {
        (bin[++i] = ((floatPart *= 2) >= 1) - 0) && --floatPart;
    }

    i = -1;
    while (++i < len && !bin[i]);

    if (bin[(lastBit = 22 + (i = (exp = 128 - i) >= -126 && exp <= 127 ? i + 1 : 128 - (exp = -127))) + 1]) {
        if (!(rounded = bin[lastBit])) {
            j = lastBit + 2;
            while (!rounded && j < len) {
                rounded = bin[j++];
            }
        }

        j = lastBit + 1;
        while (rounded && --j >= 0) {
            (bin[j] = !bin[j] - 0) && (rounded = 0);
        }
    }
    i = i - 2 < 0 ? -1 : i - 3;
    while(++i < len && !bin[i]);
    (exp = 128 - i) >= -126 && exp <= 127 ? ++i : exp < -126 && (i = 255, exp = -127);
    (intPart || status !== 0) && (exp = 128, i = 129, status == -Infinity ? signal = 1 : (status !== status) && (bin[i] = 1));

    n = Math.abs(exp + 127);
    exponent = 0;
    j = 0;
    while (j < 8) {
        exponent += (n % 2) << j;
        n >>= 1;
        j++;
    }

    var mantissa = 0;
    n = i + 23;
    for (; i < n; i++) {
        mantissa = (mantissa << 1) + bin[i];
    }
    return ((signal ? 0x80000000 : 0) + (exponent << 23) + mantissa) | 0;
}
(function() {
    function NumberToArrayBuffer() {
        // Create 1 entry long Float64 array
        return [new Float64Array([this]).buffer];
    }
    function NumberFromArrayBuffer(buffer) {
        // Off course, the buffer must be at least 8 bytes long, otherwise this is a parse error
        return new Float64Array(buffer, 0, 1)[0];
    }
    if(Number.prototype.toArrayBuffer)  {
        console.warn("Overriding existing Number.prototype.toArrayBuffer - this can mean framework conflict, new WEB API conflict or double inclusion.");
    }
    Number.prototype.toArrayBuffer = NumberToArrayBuffer;
    Number.prototype.fromArrayBuffer = NumberFromArrayBuffer;
    // Hide this methods from for-in loops
    Object.defineProperty(Number.prototype, "toArrayBuffer", {enumerable: false});
    Object.defineProperty(Number.prototype, "fromArrayBuffer", {enumerable: false});
})();