如何在Javascript中将浮点数转换为二进制表示形式(IEEE 754)?
在Javascript中将浮点数转换为二进制表示的最简单方法是什么?(例如,1.0->0x3F800000) 我尝试过手动操作,这在某种程度上是可行的(使用普通数字),但对于非常大或非常小的数字(无范围检查)和特殊情况(NaN、无穷大等)都失败了:如何在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
函数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});
})();