c - 在C语言中创建自己的函数以从字符串编码数字转换为浮点数
问题描述
我正在尝试做一个简单的函数,使用下面的函数(也附上),将一个以字符串形式编码的数字转换为浮点数,而不使用函数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;
}
解决方案
一个问题是精度。Afloat
根本不是很精确。为了通过您的测试用例,请从 更改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
是因为我以另一种方式使用它们。如果这对您来说不是一个可行的选择,您可以将它们更改为浮点类型,但这可能会导致精度损失。
uint16_t
使用and是有原因的float
,但你将不得不忍受这些限制。就是那样子。
推荐阅读
- python - 在服务器之间混合的全局变量,python 不和谐
- r - 如何使用经验 copula 计算概率?
- rust - 为什么 svd2rust 生成的一些寄存器函数使用 unsafe 而其他的却没有?
- arrays - 我有一个 18*9 的矩阵,我想计算每行 6 行的平均值并得到一个 3*9 的结果矩阵
- python-3.x - Dask gridsearch给出错误KeyError:'finalize-c53697b4-1572-4d19-af41-c76b531699b9'
- processing - 我希望用户在文本框中输入文本,我该怎么做?
- node.js - 尝试使用 Alexa 和 AWS SES 发送电子邮件。电子邮件将发送,但 Alexa 将返回并出现错误
- random-access - bzip2 是否允许在块或流级别进行随机访问解压缩?
- javascript - 如何测试使用来自外部 API 的复杂对象的函数?
- javascript - 使用 createMuiTheme 覆盖主题覆盖中的材质 UI 阴影数组值