简体   繁体   English

将两个字符串合并到stm32上的浮点数中?

[英]Merge two string into a float on an stm32?

I receive two string values over the UART to an stm32f3 and would like to concatenate them to a float, but I actually don't see how to do this. 我通过UART收到两个字符串值到stm32f3,并希望将它们连接到一个浮点数,但我实际上看不到如何做到这一点。 Let's do this in the example below. 我们在下面的例子中这样做。

char *s1="100";
char *s2="09"; //should result in 100.09

float x=???(s1,s2);

How can I achieve this? 我怎样才能做到这一点?

I'd convert each string to an integer, then use arithmetic: 我将每个字符串转换为整数,然后使用算术:

int whole = atoi(s1);
int frac = atoi(s2);

float x = whole + frac / powf(10, strlen(s2));

The last part computes 10^strlen(s2) because "09" means 09/100, "5" means 5/10, etc. 最后一部分计算10 ^ strlen(s2),因为“09”表示09/100,“5”表示5/10等。

If powf() doesn't work on your system (as you said in a comment), you can use this (only good for small non-negative inputs but that's what you have): 如果powf()在您的系统上不起作用(正如您在评论中所说),您可以使用它(仅适用于小的非负输入,但这就是您所拥有的):

float myexp10(unsigned x)
{
    if (x == 0)
        return 1.0;

    float res = 10;
    while (--x)
        res *= 10;

    return res;
}

One approach is to print both strings into a buffer, and then use strtod to read a float back: 一种方法是将两个字符串打印到缓冲区中,然后使用strtod读取一个float

char buf[10];
sprintf(buf, "%.4s.%.4s", s1, s2);
float f = strtod(buf, NULL);
printf("%f\n", f);

Note that since 100.09 has no precise representation as a float , the result would be something close to 100.089996 . 请注意,由于100.09没有精确表示为float ,因此结果将接近100.089996

Demo. 演示。

I would concatenate the two strings, with a dot in between, and then use strtof() to extract the float number, like this: 我会连接两个字符串,中间有一个点,然后使用strtof()来提取浮点数,如下所示:

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

int main(void) {
    char *s1 = "100";
    char *s2 = "09";
    char s[strlen(s1) + 1 + strlen(s2) + 1];
    strcpy(s, s1);
    strcat(s, ".");
    strcat(s, s2);
    float result = strtof (s, NULL);
    printf("%f\n", result);
    return 0;
}

Output: 输出:

100.089996 100.089996

If that precision is not enough for you, then use strtod() , like this: 如果你的精度不够,那么使用strtod() ,如下所示:

double result = strtod (s, NULL);

Another simple but tedious approach is to store them in char array and use atof() for conversion as follows: 另一个简单但繁琐的方法是将它们存储在char数组中并使用atof()进行转换,如下所示:

#include <stdio.h>
#include <string.h> /* strlen */
#include <stdlib.h> /* atof */


float str2float(const char* s1, const char* s2)
{
    int size = strlen(s1) + strlen(s2) + 2;
    char a[size];

    for(int i = 0; i < strlen(s1); ++i)
        a[i] = s1[i];
    a[strlen(s1)] = '.';

    for(int i = strlen(s1)+1, j = 0; i < size && j < strlen(s2); ++i, ++j)
        a[i] = s2[j];

    a[size] = '\0';

    return (float)atof(a);
}

int main(void)
{
    char *s1="100";
    char *s2="09"; 

    printf("%.2f\n", str2float(s1,s2));
    return 0;
}

Consider scaling the fractional part and adding as suggest by others. 考虑缩放小数部分并按其他人的建议添加。

  char *s1="100";
  char *s2="09";
  float f1 = strtof(s1, (void*) NULL); 
  unsigned n = strlen(s2);
  float f2 = strtof(s2, (void*) NULL)/powf(10, n);
  return f1 + f2;

This is usually sufficient, yet to dig a bit deeper. 这通常就足够了,但还要深入挖掘一下。

strtof(s2, (void*) NULL)/powf(10, n); incurs a rounding with the division as the quotient, a fraction, is rarely exactly representable as a binary32 . 导致与除法的舍入作为商,一个分数,很少完全可以表示为二元32 Then the addition f1 + f2 may incur another rounding. 然后加法f1 + f2可能会产生另一个舍入。 The sum is sometimes then not the best float answer due to double rounding . 由于双舍入 ,总和有时不是最好的float答案。

To greatly reduce the chance of double rounding , code can easily use higher precision like double . 为了大大减少双舍入的可能性,代码可以轻松地使用更高的精度,如double

  float f1 = strtof(s1, (void*) NULL); 
  unsigned n = strlen(s2);
  double f2 = strtod(s2, (void*) NULL)/pow(10, n); // use higher precision
  return f1 + f2;

Alternatively code may avoid wider FP math and use exact integer math first to combine the values and then divide, incurring only 1 rounding. 或者,代码可以避免更宽的FP数学,并首先使用精确的整数数学来组合值然后除以,只产生1个舍入。 This will make for a more accurate answer once in a while. 这样可以偶尔获得更准确的答案。

  long l1 = strtol(s1, (void*) NULL, 10); 
  long l2 = strtol(s2, (void*) NULL, 10); 
  unsigned n = strlen(s2);
  long p10 = pow10(n);  // Trivial user TBD code

  long sum = l1*p10 + l2;  // Exact unless `long` overflow
  return 1.0f*sum/p10;     // `float` conversion exact for value up to about 1/FLT_EPSILON

The above works well if s1 is negative . 如果s1负数,则上述方法效果很好。 Also OK with s2 as a negative aside from more code needed to extract the digit width than strlen(s2) . 除了strlen(s2)提取数字宽度所需的更多代码之外,还可以使用s2作为否定

Else it is hard to beat a string concatenation and convert. 否则很难击败字符串连接和转换。 I recommend float strof() over double atof() as 1) atof() lacks defined behavior on overflow, 2) atof() uses double math, which may be slower. 我建议float strof()超过double atof()为1) atof()在溢出时缺少定义的行为,2) atof()使用double数学,这可能会更慢。

size_t l1 = strlen(s1);
size_t l2 = strlen(s1);
char buffer[l1 + 1 + l2 + 1];  // Or use a fixed wide buffer with test to insure fit
strcpy(buffer, s1);
buffer[l1] = '.';
strcpy(buffer + l1 + 1, s1);
return strtof(buffer, (void *) NULL);

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

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