【问题标题】:Double value that is NaN output as a string as "nan"将 NaN 作为字符串输出为“nan”的双精度值
【发布时间】:2019-07-14 18:32:18
【问题描述】:

我有一个 C/C++ 应用程序,可以将数值作为字符串写入 redis。我还有一个 Java 应用程序可以从 redis 中读取这些值。有时出于正当理由,我们最终会得到一个值为NaN-NaN 的浮点值。但是,使用sprintf(charPtr, "%e", dblVal); 时,值将输出为nan。我还用%E 尝试了相同的语句,结果是NAN。当 Java 尝试通过 Float.parseFloat()Double.parseDouble 解析时,它会抛出 NumberFormatException。

此应用程序已从 Solaris 移植到 Linux,随后经历了一些 Linux 升级,在某些时候“NaN”变成了“nan”。我不能确定最终是什么升级引入了这种行为。

我已经使用 cmath 的 std::isfinite()std::isnan() 进行了练习,最终可以定义我自己的有效 (-)NaN(-)Infinity 字符串,但这似乎不需要我重新发明标准化的 NaN 和 Infinity字符串。 Infinity 可能有点不同,因为 C 端输出 inf 而 Java 想要 Infinity

最终我需要能够解码由 Java 中的 C++ 应用程序编写的数据。 nan 和 inf 不能被 Java 解码。我的重点是 NaN,但 Infinity 是一个应该涵盖的案例。

【问题讨论】:

  • 有趣的 NaN 信息,但问题/目标是什么?

标签: java c++ c linux


【解决方案1】:

为什么不在你的 java 代码中使用类似的东西来解析双精度数?

double parseDouble(String s) throws NumberFormatException {
  try {
    return Double.valueOf(s);
  } catch (NumberFormatException e) {
    if (s.equalsIgnoreCase("nan")) {
      return Double.NaN;
    } else if (s.equalsIgnoreCase("inf") || s.equalsIgnoreCase("+inf")) {
      return Double.POSITIVE_INFINITY;
    } else if (s.equalsIgnoreCase("-inf")) {
      return Double.NEGATIVE_INFINITY;
    } else {
      throw e; // Invalid string
    }
  }
}

【讨论】:

  • 这似乎是一个合理的情况,因为它只会在首先出现错误解析的情况下进行检查,因此我们不会检查每个有效的解析。我会稍等片刻,看看是否有人对此事有其他要说的。
  • 可能值得追踪其他 libcs​​ 对这些值的用途(我认为 Windows CRT 使用类似 1.#QNAN 的东西?)并考虑它们。
  • 我们如何传递浮点的功能一直困扰着我一段时间。基本上我受制于它是如何在语言中实现的,我看不到任何一方的变化。鉴于 Java 和 libc 只是不同,您的回答涵盖了我的问题。也就是说,我认为处理 C 方面的格式可能会更有效,因为我将通过 isnan 和 isfinite 进行二进制比较,而不是 Java 中的字符串比较,但在 Java 上,只有在解析失败时才会进行比较首先。
【解决方案2】:

Linux 案例是 (a) 根据ISO/IEC 9899:2001 的正确行为:

[%e, %E]

[...] 表示无穷大或 NaN 的 double 参数以 fF 转换说明符的样式进行转换。

和文本

表示无穷大的双参数转换为[-]inf[-]infinity 中的一种样式——该样式是实现定义的。表示 NaN 的双参数被转换为 [-]nan[-]nan(n-char-sequence) 中的一种风格——哪种风格和任何 n 字符序列的含义是实现定义的。 F 转换说明符分别生成 INFINFINITYNAN,而不是 infinfinitynan。277)

即Java中最安全的方法是尝试解析双精度,如果失败,则将String小写并测试-作为第一个字符的存在,并在可能的符号之后使用.startsWith("nan").startsWith("inf")测试余数

当然,如果您需要支持不符合标准的 Windows C 运行时,这将无济于事。

【讨论】:

    【解决方案3】:

    一个可能更通用的选项是在写入 redis 时将浮点数转换为十六进制,然后在读取时转换回来。这将通过将其转换为十进制字符串来确保不会有任何精度损失,而且还涵盖了 +/-Inf 和 NaN 情况。

    这是可能的,因为双方都使用 IEEE 浮点数。

    【讨论】:

      猜你喜欢
      • 2014-07-05
      • 2012-11-07
      • 1970-01-01
      • 2014-08-11
      • 1970-01-01
      • 1970-01-01
      • 2011-11-17
      • 2012-05-31
      • 2011-08-11
      相关资源
      最近更新 更多