我需要解析一个用科学符号表示的给定类型(例如:long-long integer)。示例:
123456789012345678.3e-3
123456789012345678.3
我知道给定字符串的类型,但我不能使用strtoll,因为数字是用科学符号表示的。我所做的是使用strtod转换它,对int64_t进行错误检查,并将其强制转换回int64_t。ErrCheckInt和ErrCheckDouble对整型和浮点型进行错误检查(上溢、下溢等),并将数字强制转换为任何类型。
double res = strtod(processedStr, &end);
return (std::is_floating_point<OUT_T>::value) ? ErrCheckFloat<double, OUT_T>(res, out) : ErrCheckInt<double, OUT_T>(res, out);
问题是,当我用double解析int64_t时,我得到了一个具有正确科学符号的浮点数,1个有效位。当我再次将数字强制转换为int64_t时,我失去了精度。示例编号:
input: 123456789012345678.3
double_converted: 1.23456789012346E+17
cast_to_int64_t: 123456789012345680
expected: 123456789012345678
我知道这个数字足够长,可以用双倍精度正确表示。我可以用长双,但那不能解决问题。
我可以评估字符串,并在最后根据e表示法删除/添加数字,但处理应该非常非常快,因为代码将在嵌入式rtos中运行。我已经做了很多检查,strtod也会慢慢来。
我知道给定字符串的类型,但我不能使用strtoll,因为数字是用科学符号表示的。
您只需要调用一次,使用生成的指针来检测数字是否为xxxeyyy形式,然后再次调用strtoll
来解析指数。在我看来,这比浮点运算简单得多。
我知道这个数字足够长,可以用双倍精度正确表示。
不,您不知道,因为您的示例输入是"123456789012345678",在IEEE 754双精度中无法表示。
我可以使用长双,但这不能解决问题。
实际上,如果编译器将long double
映射到"具有64位有效位的80位扩展精度",它将解决问题:所有64位整数都可以用该格式表示。GCC和Clang在Linux上通过long double
提供了历史上的80位浮点格式,但这非常不方便,以至于在Windows上实际上被认为是不可用的(您需要更改FPU控制字,并在每次有库函数要调用时恢复它,并编写自己的数学函数来操作80位浮点值。从strtold
开始。