简体   繁体   English

将uint32浮点表示转换为uint8

[英]Convert uint32 floating point representation to uint8

Without going into too many details, I have two embedded systems, neither of which can use the floating point library. 在没有太多细节的情况下,我有两个嵌入式系统,它们都不能使用浮点库。 In between them is a mobile application, where some calculations are performed. 在它们之间是一个移动应用程序,在那里执行一些计算。 One calculation needs to keep the precision. 一次计算需要保持精度。 This value is sent to the client via Bluetooth, as a byte array. 该值作为字节数组通过蓝牙发送到客户端。 When it's received I am then storing it as a uint32. 收到它后,我将其存储为uint32。 This value is then shared again with the mobile application, where the precision is needed. 然后,再次与需要精度的移动应用程序共享该值。 There is no problem there because I am able to use Java's ByteBuffer class. 那里没有问题,因为我可以使用Java的ByteBuffer类。 The problem is I also need to share this value with a Z80 microprocessor as an uint8 because it is transmitted over a UART, and is used as an ADC count (0-255), so it loses the precision (but it's not needed on this end). 问题是我还需要将这个值与Z80微处理器作为uint8共享,因为它是通过UART传输的,并且用作ADC计数(0-255),因此它会失去精度(但不需要它)结束)。

So I am doing this in my mobile app using Java: 所以我在使用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 is then being sent in a BLE characteristic write to the BLE microcontroller. 然后, b以BLE特性写入BLE微控制器。 The BLE microcontroller then reads this buffer as a little-endian 32-bit word and stores it in a uint32 . 然后,BLE微控制器将此缓冲区读取为小端32位字,并将其存储在uint32 Looking at this uint32 in the debugger shows the correct values, and like I said above I am able to put this uint32 back into a byte array and send it to the mobile app and read it using Java's ByteBuffer class. 在调试器中查看这个uint32显示正确的值,就像我上面说的那样,我可以将这个uint32放回一个字节数组并将其发送到移动应用程序并使用Java的ByteBuffer类读取它。 This works fine, I get the correct floating point value. 这工作正常,我得到正确的浮点值。

The problem is I need the integer part of this floating point representation to send to a Z80 microprocessor over UART as a uint8 because it is used as an ADC count from 0-255. 问题是我需要这个浮点表示的整数部分作为uint8通过UART发送到Z80微处理器,因为它用作0-255的ADC计数。

So, how can I convert a floating point value that's been wrapped up into an uint32 (little endian byte order) to an uint8 losing the precision? 那么,如何将一个被包装成uint32(小端字节顺序)的浮点值转换为uint8,从而失去精度? I also know that the range is from 0-255, meaning there will never be anything greater than 255.0 to convert. 我也知道范围是0-255,这意味着转换时永远不会有大于255.0的范围。

For example if I have this: 例如,如果我有这个:

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

How can I get this without using float?: 如何在不使用float的情况下得到它?:

uint8 result = 164;

Some lightly tested code to get OP started. 一些经过轻度测试的代码可以启动OP。 Uses lots of constants to allow customization and various degrees of error checking. 使用大量常量来允许自定义和各种程度的错误检查。 OP has not addressed rounding: round to nearest, toward 0, or ??. OP没有解决舍入:舍入到最近,朝向0或??。 Following truncates toward 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;
}

Output 产量

164
254
255
255
0
1
2

Useful IEEE 754 Converter 有用的IEEE 754转换器


To round positive values to nearest (many ways to cope), ties away from zero, just look at the last bit to be shifted out. 要将正值舍入到最接近的(许多处理方式),从零开始,只需看看要移出的最后一位。

  // 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;

So you want to extract the integer part of an IEEE 754 single precision float , with no floating point operations available. 因此,您希望提取IEEE 754单精度浮点数的整数部分,而不提供浮点运算。

All you need is a few bitwise operations to extract the exponent and mantissa. 您只需要一些按位操作来提取指数和尾数。 Lightly tested code. 经过轻微测试的代码。 This code supports signed values and returns a value between -255 and 255, or INT_MIN if the absolute value is outside the permitted range; 此代码支持有符号值并返回介于-255和255之间的值,如果绝对值超出允许范围,则返回INT_MIN ; adjust your support for sign, behavior in case of overflow, etc. as needed. 根据需要调整对符号的支持,溢出时的行为等。

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;
    }
}

Assuming the float stored inside the uint32_t has the same representation format of float type on your architecture and your floats are 32 bit wide sizeof(float)==4 (this is quite a standard) you can do something like that: 假设存储在内部的浮动 uint32_t具有相同的表现形式而float式上你的架构你的彩车是32位宽sizeof(float)==4 (这是一个相当标准的),你可以做这样的事情:

float *f;

f = (float *)&fValue;

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

You declare a float pointer and point it to the location of the uint32_t . 您声明一个float指针并将其指向uint32_t的位置。

Then take the value pointed py the float pointer and attempt to cast to uint8_t 然后取值指向浮点指针,并尝试转换为uint8_t


I tried the code and can tell the assumptions above are true on macOS . 我尝试了代码并且可以告诉上面的假设在macOS上是正确的。

For example: 例如:

#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);
}

Outputs: 输出:

164

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM