3
對於我正在處理的一個簡單實用程序,我需要一個將給定十進制值轉換爲32位浮點十六進制值的腳本。例如,我知道1是3F800000,100是42C80000,但是我不知道如何用任何數字返回這些結果。如果有人知道一個簡單的公式或甚至複雜的方式去做這件事,請分享。將十進制值轉換爲32位浮點十六進制
對於我正在處理的一個簡單實用程序,我需要一個將給定十進制值轉換爲32位浮點十六進制值的腳本。例如,我知道1是3F800000,100是42C80000,但是我不知道如何用任何數字返回這些結果。如果有人知道一個簡單的公式或甚至複雜的方式去做這件事,請分享。將十進制值轉換爲32位浮點十六進制
我不知道我是否正確地得到了拐角的情況,但無論如何,這裏是一些代碼:
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
上面的第一個代碼片段缺少對非規格化數字的支持。我也不確定它是否正確處理負數。 – 2010-06-27 14:24:08
請注意:我不應該使用'Math.pow(x,y)'函數,因爲它只返回「將* x *提升到* y *的結果的實現相關近似值。 [ECMA-262,15.8.2.13] – 2010-07-24 22:10:56