将 uint32 浮点表示形式转换为 uint8
Convert uint32 floating point representation to uint8
无需赘述,我有两个嵌入式系统,都不能使用浮点库。在它们之间是一个移动应用程序,其中执行一些计算。一次计算需要保持精度。该值作为字节数组通过蓝牙发送到客户端。收到后,我将其存储为 uint32。然后,此值会再次与需要精度的移动应用程序共享。那里没有问题,因为我可以使用 Java 的 ByteBuffer class。问题是我还需要将此值作为 uint8 与 Z80 微处理器共享,因为它通过 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 class。这很好用,我得到了正确的浮点值。
问题是我需要这个浮点表示的整数部分作为 uint8 通过 UART 发送到 Z80 微处理器,因为它用作从 0-255 的 ADC 计数。
那么,如何将包装成 uint32(小端字节顺序)的浮点值转换为失去精度的 uint8?我也知道范围是从 0-255,这意味着永远不会有任何大于 255.0 的东西可以转换。
例如,如果我有这个:
uint32 fValue = 0x43246ADD; // = 164.417...
如果不使用 float 怎么得到这个?:
uint8 result = 164;
假设存储在 uint32_t
中的 float 在您的体系结构 和 [=35] 中具有与 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
的位置。
然后取浮点指针指向的值py并尝试转换为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
一些经过简单测试的代码来启动 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
要将正值四舍五入到最接近的值(有很多方法可以解决),从零开始,只需查看要移出的最后一位。
// 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;
所以你想提取 IEEE 754 single precision float 的整数部分,没有可用的浮点运算。
您只需要进行一些位运算即可提取指数和尾数。轻微测试的代码。此代码支持有符号值和 returns -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;
}
}
无需赘述,我有两个嵌入式系统,都不能使用浮点库。在它们之间是一个移动应用程序,其中执行一些计算。一次计算需要保持精度。该值作为字节数组通过蓝牙发送到客户端。收到后,我将其存储为 uint32。然后,此值会再次与需要精度的移动应用程序共享。那里没有问题,因为我可以使用 Java 的 ByteBuffer class。问题是我还需要将此值作为 uint8 与 Z80 微处理器共享,因为它通过 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 class。这很好用,我得到了正确的浮点值。
问题是我需要这个浮点表示的整数部分作为 uint8 通过 UART 发送到 Z80 微处理器,因为它用作从 0-255 的 ADC 计数。
那么,如何将包装成 uint32(小端字节顺序)的浮点值转换为失去精度的 uint8?我也知道范围是从 0-255,这意味着永远不会有任何大于 255.0 的东西可以转换。
例如,如果我有这个:
uint32 fValue = 0x43246ADD; // = 164.417...
如果不使用 float 怎么得到这个?:
uint8 result = 164;
假设存储在 uint32_t
中的 float 在您的体系结构 和 [=35] 中具有与 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
的位置。
然后取浮点指针指向的值py并尝试转换为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
一些经过简单测试的代码来启动 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
要将正值四舍五入到最接近的值(有很多方法可以解决),从零开始,只需查看要移出的最后一位。
// 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;
所以你想提取 IEEE 754 single precision float 的整数部分,没有可用的浮点运算。
您只需要进行一些位运算即可提取指数和尾数。轻微测试的代码。此代码支持有符号值和 returns -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;
}
}