【问题标题】:int64_t to double to int64_t again, loss of precisionint64_t 再次加倍到 int64_t,精度损失
【发布时间】:2015-04-16 13:16:09
【问题描述】:

我需要解析一个用科学记数法表示的给定类型(例如: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

我知道这个数字足够长,可以用双精度正确表示。我可以使用 long double 但这不能解决问题。

最后我可以评估字符串并删除/添加与 e 符号相关的数字,但处理应该非常非常快,因为代码将在嵌入式 rtos 中运行。我已经做了很多检查,strtod 也会花时间。

【问题讨论】:

    标签: c++ floating-point type-conversion floating-accuracy


    【解决方案1】:

    我知道给定字符串的类型,但我不能使用 strtoll,因为数字是以科学记数法给出的。

    只需要调用一次,使用结果指针检测数字是否为xxxeyyy形式,再次调用strtoll解析指数。在我看来,这比通过浮点要简单得多。

    我知道这个数字足够长,可以用双精度正确表示。

    不,您不知道,因为您的示例输入是“123456789012345678”,在 IEEE 754 双精度中无法表示。

    我可以使用 long double 但这不能解决问题。

    实际上,如果您的编译器将long double 映射到“80 位扩展精度和 64 位有效位”,它解决问题:所有 64 位整数都可以用这种格式表示。 GCC 和 Clang 在 Linux 上通过long double 提供了历史悠久的 80 位浮点格式,但它非常不方便,实际上被认为在 Windows 上不可用(您需要更改 FPU 控制字,并且每次都恢复它您可以调用库函数,并编写自己的数学函数来对 80 位浮点值进行运算。从 strtold 开始。

    【讨论】:

    • 并不是说如果“你的编译器”是 Visual Studio,long double 只是 double 的同义词,唉。
    • @Robinson:恕我直言,计算领域的一大悲剧是 ANSI C 未能允许可变参数函数原型指示它们是否期望所有浮点值都为double,全部为@ 987654326@ 或 long double 作为该类型,其他所有内容作为 double。在除可变参数函数之外的所有上下文中,编译器都可以使十进制文字为 long double 类型而不会破坏任何内容,但 printf 确实是一团糟。如果想要支持long double 的 printf 实现可以指定参数应该提升到那个,并且...
    • ...那些只需要 64 位浮点值的人可能会要求将浮点值强制转换为该值,这样代码就不必担心哪些值是哪种类型。有趣的是,顺便说一句,人们认为 long double 类型是 x87 的怪异之处,而在许多缺少浮点单元的系统上,它实际上是比 double 更好的计算类型。当按预期使用时,“奇数”大小不是问题,因为代码很少需要 long double 的大型数组。该类型的主要目的是进行临时计算,为此它非常出色。
    猜你喜欢
    • 1970-01-01
    • 2010-10-16
    • 2016-12-19
    • 2021-08-06
    • 2012-11-16
    • 1970-01-01
    • 2018-05-20
    • 2011-11-19
    • 1970-01-01
    相关资源
    最近更新 更多