2010-06-20 274 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

相關問題