我正在尝试做一个简单的函数,将以字符串形式编码的数字转换为 float ,使用下面的函数(也已附加),不使用函数 strtof
.
我得到了错误的值,有人可以解决这个问题吗?为什么这会给我不正确的值?
例如,如果输入字符串是 "123456789.123"
,该函数将返回浮点值 123456789.123...
我正在使用 DevC++
if string == "12345678"
output = 12345678.000000 (CORRECT)
if string == "-12345678"
output = -12345678.000000 (CORRECT)
if string == "123456789"
output = 123456792.000000 (INCORRECT)
if string == "-123456789"
output = -123456792.000000 (INCORRECT)
if string == "1000.1"
output = 999.799988 (INCORRECT)
if string == "-1000.1"
-output = -999.799988 (INCORRECT)
到目前为止我的代码是:
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
float StringToFloat (uint8_t *var);
int main()
{
uint8_t string[64] = "-1000.1";
float value = StringToFloat (string);
printf("%f", value);
return 0;
}
float StringToFloat (uint8_t *var)
{
float multiplier;
float result = 0;
bool negative_num = false;
bool found_comma_or_dot = false;
uint16_t numbers_before_dot = 0;
uint16_t numbers_after_dot = 0;
uint16_t i = 0;
while (*(var+i) != 0)
{
if (*(var+i) == '-') { negative_num = true; }
else if (*(var+i) == '.' || *(var+i) == ',') { found_comma_or_dot = true; }
else
{
if (found_comma_or_dot == false) { numbers_before_dot++; }
if (found_comma_or_dot == true) { numbers_after_dot++; }
}
i++;
}
multiplier = pow (10, numbers_before_dot-1);
while (*var != 0)
{
if (*var == '-') { var++; }
if (numbers_before_dot > 0)
{
numbers_before_dot--;
result += ( (*var) - 0x30) * (multiplier);
multiplier /= 10;
}
else if (numbers_after_dot > 0)
{
numbers_after_dot--;
result += ( (*var) - 0x30) * (multiplier);
multiplier /= 10;
}
var++;
}
if (negative_num == true)
{
result *= (-1);
}
return result;
}
最佳答案
一个问题是精度。 float
不是很精确。为了通过您的测试用例,将 float
更改为 double
。如果您运行此代码,可以看到这一点:
float t = 123456789;
printf("%f\n", t);
您的代码过于复杂。这是一个更巧妙的解决方案。
double StringToFloat(uint8_t *var)
{
// First check if negative. If it is, just step one step forward
// and treat the rest as a positive number. But remember the sign.
double sign = 1;
if(*var=='-') {
sign = -1;
var++;
}
// Read until either the string terminates or we hit a dot
uint32_t integer_part = 0;
while(*var != 0) {
if(*var == '.' || *var == ',') {
var++;
break;
}
integer_part = 10*integer_part + (*var - '0');
var++;
}
// If we hit the string terminator in previous loop, we will do so
// in the beginning of this loop too. If you think it makes things
// clearer, you can add the boolean found_comma_or_dot to explicitly
// skip this loop.
uint32_t decimal_part = 0;
uint32_t decimal_size = 0;
while(*var != 0) {
decimal_part = 10*decimal_part + (*var - '0');
var++;
decimal_size++;
}
return sign * (integer_part + decimal_part/pow(10, decimal_size));
}
请注意,我将 uint16_t
更改为 uint32_t
因为我以另一种方式使用它们。如果这对您来说不可行,您可以将它们更改为 float 类型,但这可能会导致精度损失。
使用 uint16_t
和 float
是有原因的,但您将不得不忍受这些限制。就是这样。
关于在C语言中创建自己的函数将字符串编码数字转换为 float ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58655490/