将十进制值转换为 32 位浮点十六进制 [英] Converting a decimal value to a 32bit floating-point hexadecimal

查看:40
本文介绍了将十进制值转换为 32 位浮点十六进制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于我正在开发的一个简单实用程序,我需要一个脚本来将给定的十进制值转换为 32 位浮点十六进制值.例如,我知道 1 是 3F800000,100 是 42C80000,但是我不知道如何用任何数字返回这些结果.如果有人知道执行此操作的简单公式甚至复杂方法,请分享.

For a simple utility I'm working on, I need a script that converts a given decimal value to a 32bit floating-point hexadecimal value. For example, I know 1 is 3F800000 and 100 is 42C80000, however I don't know how to return these results with any number. If somebody knows a simple formula or even a complex way to go about doing this, please share.

推荐答案

我不知道我是否正确理解了极端情况,但无论如何,这里有一些代码:

I don't know if I got the corner cases correctly, but anyway, here is some code:

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 节,最后一段.)

The funny-looking 0|0x... expressions are necessary because JavaScript treats these literal numbers as being large positive integers, but applying a bitwise operator apparently converts them to signed 32-bit ints. (Compare the ECMAScript specification, section 8.5, last paragraph.)

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

Update: The following code is based on the above code, but it is more aligned to the actual wording of the specification. Additionally, it is independent of the particular floating point type that is used to implement JavaScript's Number. The code first moves the value to the interval [1.0; 2.0), since this is the representation that is mentioned in IEEE 754-1985 for normalized numbers. This code also handles denormalized numbers correctly and all the operations it uses are defined in IEEE 754-1985 and are exact, that is they don't lose precision.

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

这篇关于将十进制值转换为 32 位浮点十六进制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆