将uint32浮点表示转换为uint8

时间:2016-11-04 18:49:28

标签: c type-conversion uint32

没有太多细节,我有两个嵌入式系统,它们都不能使用浮点库。在它们之间是一个移动应用程序,在那里执行一些计算。一次计算需要保持精度。该值作为字节数组通过蓝牙发送到客户端。收到它后,我将其存储为uint32。然后,再次与需要精度的移动应用程序共享该值。那里没有问题,因为我可以使用Java的ByteBuffer类。问题是我还需要将这个值与Z80微处理器作为uint8共享,因为它是通过UART传输的,并且用作ADC计数(0-255),因此它会失去精度(但不需要它)端)。

所以我在使用Java的移动应用程序中执行此操作:

int bits = Float.floatToIntBits(fAdcCount);
byte[] b = new byte[4];
b[0] = (byte)(bits & 0xff);
b[1] = (byte)((bits >> 8) & 0xff);
b[2] = (byte)((bits >> 16) & 0xff);
b[3] = (byte)((bits >> 24) & 0xff);
然后

b以BLE特性写入BLE微控制器发送。然后,BLE微控制器将此缓冲区作为小端32位字读取,并将其存储在uint32中。在调试器中查看此uint32会显示正确的值,就像我上面说的那样,我可以将此uint32放回到字节数组中并将其发送到移动应用程序并使用Java的ByteBuffer读取它类。这工作正常,我得到正确的浮点值。

问题是我需要将此浮点表示的整数部分作为uint8通过UART发送到Z80微处理器,因为它用作0-255的ADC计数。

那么,我怎样才能将一个被包装成uint32(小端字节顺序)的浮点值转换为uint8而失去精度呢?我也知道范围是从0到255,这意味着永远不会有大于255.0的转换。

例如,如果我有这个:

uint32 fValue = 0x43246ADD; // = 164.417...

如何在不使用float的情况下获得此功能?:

uint8 result = 164;

3 个答案:

答案 0 :(得分:4)

一些经过轻度测试的代码可以启动OP。使用大量常量来允许自定义和各种程度的错误检查。 OP没有解决舍入:舍入到最近,朝向0或??。截断为0。

#include <stdint.h>
#define MANTISSA_BIT_WIDTH 23
#define BIASED_EXPO_MAX 255
#define EXPO_BIAS 127
#define SIGN_MASK 0x80000000

unsigned DN_float_to_uint8(uint32_t x) {
  if (x & SIGN_MASK) return 0; // negative
  int expo = (int) (x >> MANTISSA_BIT_WIDTH);
  if (expo == 0) return 0;  // sub-normal
  if (expo == BIASED_EXPO_MAX) return 255;  // Infinity, NaN
  expo -= EXPO_BIAS;
  if (expo > 7) return 255; // too big
  if (expo < 0) return 0; // wee number
  uint32_t mask = ((uint32_t)1 << MANTISSA_BIT_WIDTH) - 1;
  uint32_t mantissa = mask & x;
  mantissa |= mask + 1;
  mantissa >>= (MANTISSA_BIT_WIDTH - expo);
  return mantissa;
}

#include <stdio.h>
int main() {
  printf("%u\n", DN_float_to_uint8(0x43246a00)); // 164
  printf("%u\n", DN_float_to_uint8(0x437e0000)); // 254
  printf("%u\n", DN_float_to_uint8(0x437f0000)); // 255
  printf("%u\n", DN_float_to_uint8(0x43800000)); // 256
  printf("%u\n", DN_float_to_uint8(0x3f7fffff)); // 0.99999994
  printf("%u\n", DN_float_to_uint8(0x3f800000)); // 1
  printf("%u\n", DN_float_to_uint8(0x40000000)); // 2
  return 0;
}

输出

164
254
255
255
0
1
2

有用的IEEE 754 Converter

要将正值舍入到最接近的(许多处理方式),与零相关,只需查看要移出的最后一位。

  // mantissa >>= (MANTISSA_BIT_WIDTH - expo);
  // return mantissa;

  // shift as needed expect for 1 bit
  mantissa >>= (MANTISSA_BIT_WIDTH - expo - 1);
  // now shift last bit
  mantissa = (mantissa + 1) >> 1;
  // Handle special case
  if (mantissa >= 256) mantissa = 255;
  return mantissa;

答案 1 :(得分:2)

所以你想要提取IEEE 754 single precision float的整数部分,没有可用的浮点运算。

您需要的只是一些按位操作来提取指数和尾数。经过轻微测试的代码。此代码支持有符号值,并返回介于-255和255之间的值,如果绝对值超出允许范围,则返回INT_MIN;根据需要调整对符号的支持,溢出时的行为等。

int integer_part_of_single_float(uint32_t f)
{
    uint32_t mantissa = (f & 0x7fffff) | 0x800000;
    uint8_t exponent = f >> 23;
    if (exponent < 127) {
        return 0;
    } else if (exponent >= 135) {
        return INT_MIN;
    } else {
        unsigned absolute_value = mantissa >> (22 - (exponent - 128));
        return mantissa & 0x80000000 ? -absolute_value : absolute_value;
    }
}

答案 2 :(得分:0)

假设uint32_t中存储的 float 在您的架构上具有相同的float类型的表示格式,则您的浮点数为32位宽sizeof(float)==4(这是相当标准的)你可以做类似的事情:

float *f;

f = (float *)&fValue;

if( *f <= 255 && *f >= 0 )
{
    result = (uint8_t) (*f);
}
else
{
    // overflow / undeflow
}

您声明float指针并将其指向uint32_t的位置。

然后取浮点指针的值,并尝试转换为uint8_t

我尝试了代码,可以在 macOS 上说出上述假设是正确的。

例如:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    uint32_t fValue = 0x43246ADD;
    uint8_t result=0;

    float *f;

    f = (float *)&fValue;

    if( *f <= 255 && *f >= 0 )
    {
        result = (uint8_t) (*f);
    }
    else
    {
        // overflow / undeflow
    }

    printf("%d\n", result);
}

输出:

164