1

我需要将 32 位 IEEE754 浮点数转换为有符号的 Q19.12 定点格式。问题是它必须以完全确定的方式完成,所以通常的 (int)(f * (1 << FRACTION_SHIFT)) 是不合适的,因为它使用非确定性浮点数学。是否有任何“位摆弄”或类似的确定性转换方法?

编辑:在这种情况下确定性假设为:给定相同的浮点数据在不同平台上实现完全相同的转换结果。

4

3 回答 3

3

浮点数不是非确定性的。你从哪里得到这个荒谬的假设?

扩展一点: 1 << FRACTION_SHIFT是 2 的精确幂,因此以浮点数精确表示。乘以 2 的精确幂是精确的(除非发生上溢/下溢,但在这种情况下,无论如何都没有有意义的定点表示,所以你不在乎)。因此,唯一可能的舍入来源是转换为整数,这完全由 C# 指定;因此,结果不仅是确定性的,而且您将获得可移植的相同结果。

于 2012-07-18T13:44:39.850 回答
3

虽然@StephenCanon 的回答可能是关于这个特定情况完全确定性的正确答案,但我决定保持更安全的一面,仍然手动进行转换。这是我最终得到的代码(感谢@CodesInChaos 提供有关如何执行此操作的指针):

public static Fixed FromFloatSafe(float f) {
    // Extract float bits
    uint fb = BitConverter.ToUInt32(BitConverter.GetBytes(f), 0);
    uint sign = (uint)((int)fb >> 31);
    uint exponent = (fb >> 23) & 0xFF;
    uint mantissa = (fb & 0x007FFFFF);

    // Check for Infinity, SNaN, QNaN
    if (exponent == 255) {
        throw new ArgumentException();
    // Add mantissa's assumed leading 1
    } else if (exponent != 0) {
        mantissa |= 0x800000;
    }

    // Mantissa with adjusted sign
    int raw = (int)((mantissa ^ sign) - sign);
    // Required float's radix point shift to convert to fixed point
    int shift = (int)exponent - 127 - FRACTION_SHIFT + 1;

    // Do the shifting and check for overflows
    if (shift > 30) {
        throw new OverflowException();
    } else if (shift > 0) {
        long ul = (long)raw << shift;
        if (ul > int.MaxValue) {
            throw new OverflowException();
        }
        if (ul < int.MinValue) {
            throw new OverflowException();
        }
        raw = (int)ul;
    } else {
        raw = raw >> -shift;
    }

    return Fixed.FromRaw(raw);
}
于 2012-07-19T15:03:23.957 回答
1

If determinism is absolutely required, I'd parse the content as an integer, and do the conversion manually.

First extract the exponent. If it's too small return 0, if it's too large, throw an overflow exception.

Next extract sign and mantissa (remember the implicit leading 1). If the sign bit is 1, flip the sign of the mantissa. Finally execute a bit shift by the exponent combined with a bias.

I also wrote a soft float implementation, that guarantees determinism. It's pretty incomplete, but the parts you need are implemented.

于 2012-07-18T13:56:40.990 回答