我正在尝试实现一个执行以下操作的 c 函数:
输入:
float f= 8.947563;
输出:
uint32_t o1 = 8;
uint32_t o2 = 947563;
我想将这些结果中的每一个存储在特定的寄存器中。
我找到了一些解决方案,例如 modf 函数,但它并没有真正解决我的问题,因为它的 o2 将是 0.947563 而不是 947563。 此外,分数后面的位数可能会根据用户输入而有所不同,因此我不能简单地设置一个规则将 0.947563 乘以 1000000,因为它不适用于具有较大分数的数字,例如 8.947556333。
知道如何解决这个问题吗? 谢谢。
函数modff
将float
分解为整数和分数部分(modf
表示double
(。如果您需要将.947563f
转换为整数947563
,则必须执行某种技巧。
一种通用的方法是将浮点文本转换为字符串,然后对其进行解析。例:
#include <stdio.h>
static int modff_int (const char* value, int* iptr)
{
int fractional;
sscanf(value, "%d.%d", &fractional, iptr);
return fractional;
}
#define FLOAT_TO_STR(f) #f // simplified version that only works with float literals
int main (void)
{
int integral;
const char* str = FLOAT_TO_STR(8.947563f);
int fractional = modff_int(str, &integral);
printf("Integral: %dn", integral);
printf("Fractional: %dn", fractional);
}
然而,这比简单地将浮点数.947563f
乘以一个常数要慢得多。
让我们看一些浮点示例:
1.5
0x3FC00000
0 01111111 10000000000000000000000
1.10000000000000000000000<<0
1.10000000000000000000000
1.8
0x3FE66666
0 01111111 11001100110011001100110
1.10000000000000000000000<<0
1.10000000000000000000000
2.1
0x40066666
0 10000000 00001100110011001100110
1.00001100110011001100110<<1
10.0001100110011001100110
12.3456
0x41458794
0 10000010 10001011000011110010100
1.10001011000011110010100<<3
1100.01011000011110010100
那么,你想得到什么呢?
12.3456 1100.01011000011110010100 你的两个uint32_ts是0b1100和0b01011000011110010100,前者是你想要的形式,但后者呢? 您的示例是十进制的,当然与计算机上的浮点数无关。
您的号码 8.947563
0x410F2938
0 10000010 00011110010100100111000
1.00011110010100100111000<<3
1000.11110010100100111000
f = 8.947563
o1 = 1000
o2 = 00000000000011100111010101101011
但
11110010100100111000
11100111010101101011
不相等。 前者是分数,因此需要进行一些操作。
11110010100100111000/100000000000000000000*11110100001001000000
但
0xF2938 * 0xF4240
不适合 32 位,因此我们必须将其升级到 64 位。
0000000000000000000000001110011101010110101100101011111000000000/100000000000000000000
这就是O2的来源,当你做10个基数数学时
1110011101010110101100101011111
11100111010101101011
本来可以完成 32 位
0xF293*0xF424
11100111010101100011100010101100
并切断前 20 位,您得到947563 O2
11100111010101100011100010101100
11100111010101101011
因此,如果您总是想要 6 位数字,那么取分数乘以 1000000 并从底部修剪掉正确数量的位数。 对于单个尾数,尾数开始为 23 位,对于您的数字,指数为 3,因此尾数中剩余 20 位作为分数。 上面欺骗了一些你想将这些数字调整为已知对齐方式,就像你在做普通浮点数学时一样,例如
0xF2938000*0xF4240000;
给
1110011101010110101100101011111000000000000000000000000000000000
我们砍掉前 32 位:
11100111010101101011001010111110
然后取前 20 位:
11100111010101101011 result
11100111010101101011 o2
0xF2938 * 0xF4240同样很好0xF293*0xF424可能会给出与预期不同的结果。
如果这是您想要的,十进制中的 6 位数字,然后这样做:
double x, y, z;
uint32_t a,b;
x = 8.947563;
y = modf(x, &z);
a = z;
b = y*1000000.0;
printf("%u %un",a,b);
这给了:
8 947563
我会让你整理出负数。
正如您现在所说,该值是纳秒分辨率的秒,您需要删除整数部分并将其保留为 o1,然后乘以 1E9,加上 0.5,然后将整数部分作为 o2。添加 0.5 是四舍五入到最接近的纳秒,而不是截断。 请注意,变量f
应该是double
而不是float
,因为float
只能存储大约 7 位有效数字。
#define TEN_POWER_9 ((double)(1e9))
o1 = int(f) ;
o2 = int(((f - (double)o1) * TEN_POWER_9) + 0.5) ;
通常我不使用 c,所以我不知道是否有正确的方法来做你想要的。但是,如果您将浮点数转换为字符串并在点处拆分它们,然后将两者转换回整数或长整型或任何您想要的内容,该怎么办?我知道这听起来不太好,但我认为这可以奏效。