首页 > 解决方案 > 在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;
}

标签: cstringfloating-point

解决方案


一个问题是精度。Afloat根本不是很精确。为了通过您的测试用例,请从 更改floatdouble。如果您运行以下代码,可以看到这一点:

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_tuint32_t是因为我以另一种方式使用它们。如果这对您来说不是一个可行的选择,您可以将它们更改为浮点类型,但这可能会导致精度损失。

uint16_t使用and是有原因的float,但你将不得不忍受这些限制。就是那样子。


推荐阅读