如何仅使用math.h将字符串转换为双精度浮点数

5
我正在尝试将字符串转换为双精度浮点数,但由于我正在开发一个Windows本地应用程序(仅链接到ntdll.dll),因此我没有大部分标准库可用。我可以使用math.h中的基本FP支持,但那基本上就是这样了。
如何将字符串转换为最接近该字符串表示的有理数的双精度浮点数?

你可以搜索 "strtod" 的源代码并复制它们。请注意许可证!(strtod 是 C 语言中将字符串转换为双精度浮点数的函数)。我看了一个版本,似乎写起来并不是很困难。 - xanatos
@xanatos,我在提问之前确实查看了glibc源代码;然而,该算法涉及多精度算术(如果有的话,它是基于哪篇论文的当然很难理解)。 - avakar
3个回答

5

谢谢!看起来我不能不引入任意精度算术就做到它。 - avakar
lipforge.ens-lyon.fr/projects/crlibm 可能对你有帮助。 - AProgrammer

2

你看过Open NT Native Template Library吗?特别是STLx部分。基本上,你可以在Native或Kernel代码中得到接近正常C++运行时的东西。


1

假设JSON语法(链接目前无法访问,这里是Google缓存版本)对您来说是可接受的,下面的内容基本上直接来自于内部开发的JSON解析代码,是其语法图的文字实现:

/*

    defined functions for handling the input:

        nextChar() - peeks at the next character of input

        getAndRemoveCharacter() - returns the next character of input and
        dequeues it

    This code also assumes you have BOOL, YES and NO defined; I've left this in
    for clarity
*/

double getNumber()
{
    // determine whether the number is negative - it'll start with a '-' if so
    BOOL negative = NO;
    if(nextChar() == '-')
    {
        negative = YES;
        getAndRemoveCharacter();
    }

    // seed the output number to 0
    double number = 0.0;

    // if the next character isn't a '0' then this is the number proper, so
    // just pull off the digits and assemble the number; otherwise this number
    // is either 0 itself (in which case the initial seed is correct) or a
    // decimal starting in 0
    if(nextChar() != '0')
    {
        while(nextChar() >= '0' && nextChar() <= '9')
        {
            number *= 10.0;
            number += getAndRemoveCharacter() - '0';
        }
    }
    else
        getAndRemoveCharacter();

    // if this is a decimal then jump on to the decimal part and deserialise
    // digits, much as above
    if(nextChar() == '.')
    {
        getAndRemoveCharacter();
        double decimalMultiplier = 1.0;
        while(nextChar() >= '0' && nextChar() <= '9')
        {
            decimalMultiplier /= 10.0;
            number += (double)(getAndRemoveCharacter() - '0') * decimalMultiplier;
        }
    }

    // if this number has an exponent then deal with that
    if(nextChar() == 'e' || nextChar() == 'E')
    {
        getAndRemoveCharacter();

        double exponent = 0.0;
        BOOL exponentPositive = YES;

        // JSON allows positive exponents to start with + (unlike
        // the mantissa) and requires negative exponents to start with -
        if(nextChar() == '+')
        {
            getAndRemoveCharacter();
        }
        else
            if(nextChar() == '-')
            {
                exponentPositive = NO;
                getAndRemoveCharacter();
            }

        // read out digits and assemble exponent
        while(nextChar() >= '0' && nextChar() <= '9')
        {
            exponent *= 10.0;
            exponent += getAndRemoveCharacter() - '0';
        }

        // apply exponent
        number *= pow(10.0, exponentPositive ? exponent : -exponent);
    }

    // negate if necessary and return
    return negative ? -number : number;
}

任何将ASCII字母放在正常ASCII范围内的字符类型都可以使用,因此它应该在ASCII和变体以及Unicode上同样有效。我猜你可能只想直接将字符串作为参数传递,而不是进行所有这些调用;它们在原始代码中存在,因为输入流来自远方,所以它们可能会阻塞。

'pow'中使用的仅有的math.h函数,其他都是基本操作。


同意。我根据“我没有大部分标准库可用”的问题提供的上下文来修改了“最接近”的含义,使其成为一个明确的提示,表明传入的数字不会按照双精度的精度和范围进行格式化。所提供的代码可能与atof一样好,例如,我理解任务是提供标准C库通常会提供的内容。 - Tommy
@AProgrammer 我的感觉是,IEEE浮点标准或C99标准并不要求这样做,因此很少有人这样做。但这并不是要反对您的意见,我注意到在没有真正阅读strtod的glibc实现(http://sourceware.org/git/?p = glibc.git; a = blob_plain; f = stdlib / strtod_l.c; hb = HEAD)的情况下,许多与多精度相关的代码片段跳了出来。因此,您的情况似乎比我的强得多。 - Tommy
1
C标准对浮点常量的要求被strtod()和atof()继承,其要求是“结果要么是最接近可表示值,要么是紧邻最接近可表示值的较大或较小可表示值之一,在实现定义的方式下选择”。我相信,一个完全符合标准的strtod()历史上一直是C标准中最棘手的部分之一。 - caf
1
准确地说,这意味着 strtod 函数可以返回一个仅次于最接近值而非最接近值的结果。 - Tommy
@Tommy,我认为要实现这一点,你必须使用多精度算术。 - AProgrammer
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接