2010-06-20 222 views
3

对于我正在处理的一个简单实用程序,我需要一个将给定十进制值转换为32位浮点十六进制值的脚本。例如,我知道1是3F800000,100是42C80000,但是我不知道如何用任何数字返回这些结果。如果有人知道一个简单的公式或甚至复杂的方式去做这件事,请分享。将十进制值转换为32位浮点十六进制

回答

3

我不知道我是否正确地得到了拐角的情况,但无论如何,这里是一些代码:

function floatToIntBits(f) { 
    var NAN_BITS = 0|0x7FC00000; 
    var INF_BITS = 0|0x7F800000; 
    var ZERO_BITS = 0|0x00000000; 
    var SIGN_BIT = 0|0x80000000; 
    var EXP_MASK = 0|0x7F800000; 
    var MANT_MASK = 0|0x007FFFFF; 

    if (f != f) 
     return NAN_BITS; 

    var signBit = (f > 0.0 || (f == 0.0 && Math.pow(f, -1) > 0)) ? 0 : SIGN_BIT; 
    var fabs = Math.abs(f); 
    if (fabs == Number.POSITIVE_INFINITY) 
     return signBit | INF_BITS; 
    if (fabs == 0.0) 
     return signBit | ZERO_BITS; 

    var e = 0, x = f; 
    while (x != 0.0) { 
     e++; 
     x /= 2.0; 
    } 

    var exp = e - (1023 + 52); 
    if (exp >= 127) // XXX: maybe incorrect 
     return signBit | INF_BITS; 
    if (exp <= -126) // XXX: maybe incorrect 
     return signBit | ZERO_BITS; 

    var ceil = Math.pow(2.0, exp); 
    //console.log("fabs", fabs, "ceil", ceil); 
    var mantissa = fabs/ceil * Math.pow(2.0, 24); 
    if (fabs == ceil) { 
     mantissa = 0; 
    } else { 
     exp--; 
    } 
    var expBits = ((exp + 127) << 23) & EXP_MASK; 
    var mantissaBits = mantissa & MANT_MASK; 

    //console.log("sign", signBit, "expBits", expBits.toString(16), "mantissaBits", mantissaBits.toString(16)); 
    return signBit | expBits | mantissaBits; 
} 

function testCase(expected, f) { 
    var actual = floatToIntBits(f); 
    if (expected !== actual) { 
     console.log("expected", expected.toString(16), "actual", actual.toString(16), "f", f); 
    } 
} 

testCase(0|0x80000000, -0.0); 
testCase(0|0x00000000, 0.0); 
testCase(0|0x3F800000, 1.0); 
testCase(0|0x42C80000, 100.0); 
testCase(0|0x7FC00000, 0.0/0.0); 
testCase(0|0x7F800000, 1.0/0.0); 
testCase(0|0xFF800000, 1.0/-0.0); 

有趣的前瞻性0|0x...表达是必要的,因为JavaScript将这些文字数为较大的正整数,但应用按位运算符显然会将它们转换为带符号的32位整数。 (比较ECMAScript规范,第8.5节,最后一段)。

更新:以下代码基于上述代码,但它更符合规范的实际措辞。此外,它独立于用于实现JavaScript的特定浮点类型Number。代码首先将值移至区间[1.0; 2.0),因为这是IEEE 754-1985中为归一化数字提到的表示。这段代码也可以正确处理非规范化的数字,它所使用的所有操作都在IEEE 754-1985中定义,并且是精确的,即它们不会失去精度。

function assert(cond, msg, arg0) { 
    if (!cond) 
     console.log("error", msg, arg0); 
} 

function floatToIntBits(f) { 
    var NAN_BITS = 0|0x7FC00000; 
    var INF_BITS = 0|0x7F800000; 
    var ZERO_BITS = 0|0x00000000; 
    var SIGN_MASK = 0|0x80000000; 
    var EXP_MASK = 0|0x7F800000; 
    var MANT_MASK = 0|0x007FFFFF; 
    var MANT_MAX = Math.pow(2.0, 23) - 1.0; 

    if (f != f) 
     return NAN_BITS; 
    var hasSign = f < 0.0 || (f == 0.0 && 1.0/f < 0); 
    var signBits = hasSign ? SIGN_MASK : 0; 
    var fabs = Math.abs(f); 

    if (fabs == Number.POSITIVE_INFINITY) 
     return signBits | INF_BITS; 

    var exp = 0, x = fabs; 
    while (x >= 2.0 && exp <= 127) { 
     exp++; 
     x /= 2.0; 
    } 
    while (x < 1.0 && exp >= -126) { 
     exp--; 
     x *= 2.0; 
    } 
    assert(x * Math.pow(2.0, exp) == fabs, "fabs"); 
    var biasedExp = exp + 127; 
    assert(0 <= biasedExp && biasedExp <= 254, biasedExp); 

    if (biasedExp == 255) 
     return signBit | INF_BITS; 
    if (biasedExp == 0) { 
     assert(0.0 <= x && x < 2.0, "x in [0.0, 1.0)", x); 
     var mantissa = x * Math.pow(2.0, 23)/2.0; 
    } else { 
     assert(1.0 <= x && x < 2.0, "x in [0.5; 1.0)", x); 
     var mantissa = x * Math.pow(2.0, 23) - Math.pow(2.0, 23); 
    } 
    assert(0.0 <= mantissa && mantissa <= MANT_MAX, "mantissa in [0.0, 2^23)", mantissa); 

    //console.log("number", f, "x", x, "biasedExp", biasedExp, "mantissa", mantissa.toString(16)); 
    var expBits = (biasedExp << 23) & EXP_MASK; 
    var mantissaBits = mantissa & MANT_MASK; 

    //console.log("number", f, "sign", signBits.toString(16), "expBits", expBits.toString(16), "mantissaBits", mantissaBits.toString(16)); 
    return signBits | expBits | mantissaBits; 
} 

function testCase(expected, f) { 
    var actual = floatToIntBits(f); 
    if (expected !== actual) { 
     console.log("error", "number", f, "expected", expected.toString(16), "got", actual.toString(16)); 
    } 
} 

testCase(0|0xFF800000, 1.0/-0.0); // -Inf 
testCase(0|0xBF800000, -1.0); 
testCase(0|0x80000000, -0.0); 
testCase(0|0x00000000, 0.0); 
testCase(0|0x00000001, Math.pow(2.0, -(126 + 23))); // minimum denormalized 
testCase(0|0x007FFFFF, Math.pow(2.0, -126) - Math.pow(2.0, -(126 + 23))); // maximum denormalized 
testCase(0|0x00800000, Math.pow(2.0, -126)); // minimum normalized float 
testCase(0|0x3F800000, 1.0); 
testCase(0|0x42C80000, 100.0); 
testCase(0|0x7F800000, 1.0/0.0); // Inf 
testCase(0|0x7FC00000, 0.0/0.0); // NaN 
+0

上面的第一个代码片段缺少对非规格化数字的支持。我也不确定它是否正确处理负数。 – 2010-06-27 14:24:08

+0

请注意:我不应该使用'Math.pow(x,y)'函数,因为它只返回“将* x *提升到* y *的结果的实现相关近似值。 [ECMA-262,15.8.2.13] – 2010-07-24 22:10:56

相关问题