【问题标题】:sybase 15.7 float to numeric rounding errorsybase 15.7 浮点数舍入错误
【发布时间】:2015-01-18 21:55:14
【问题描述】:

任何人都可以解释以下内容,在我看来这只是一个错误:

select convert(numeric(8,4), convert(float, '12.4155499999999996418864611769'))

12.4156

答案当然应该是 12.4155。 为了仔细检查,我创建了一个表 MyTab,其中包含一个 sybase“float”列并插入了“12.4155499999999996418864611769”。然后使用转换转储十六进制并得到 0x4028D4C2F837B4A2。这确实是我插入的字符串的 IEEE 754 双精度表示。然后,如果我(如上)将其转换为数字(8,4),则为 12.4156。

这是我认为的错误,还是我要疯了?

【问题讨论】:

    标签: floating-point sap-ase


    【解决方案1】:

    在 Sybase 中从双精度转换为十进制时,您可能会遇到 double-rounding 错误。

    很可能使用的算法是首先打印 IEEE 754 数字(在您的情况下,由 0x4028D4C2F837B4A2 表示),例如精度为 17 位十进制数字,因为这个数字在某种意义上是IEEE 754 双精度格式的“十进制精度”。对于您的示例,此转换为十进制的结果是 12.415550000000000。

    然后,由于您要求在点后输入 4 个十进制数字,因此中间十进制表示会四舍五入,在 ties-go-up 或 ties-go-to-nearest-even 下。无论如何,两者都是错误的,因为第一次舍入丢失了一些关键信息(即,原始数字略低于 12.41555,不完全是)。

    我不熟悉 Sybase,但很可能没有简单的解决方法。您可能需要使用足够的无关数字转换为十进制以避免该问题(即 21 个额外数字,见下文),但您可以期望 17 号之后的数字打印为“0”,原因与您得到双倍的原因相同- 首先是四舍五入的十进制转换。您可以从您拥有的双精度数中减去 12(该操作恰好是精确的,即不引入任何近似值)以便在转换为十进制时获得几位数字,但这不足以确保所有双精度值的正确舍入。

    注意事项:

    1. 作为参考,我们所说的双精度数的准确值为12.415549999999999641886461176909506320953369140625。

    2. 根据 Mark Dickinson 的回答this question。 The number in your question is a good candidate for the maximum number of consecutive nines in a double, but it pales in front of Mark's 2.12818792307269553358078502102171540639252016258831784842556110831434197718043638405555406495645619729155240037555858106390933161420388023706431461384056688295540725831155392678607931808851292893574214797681879999999999999999999941026584542575391157788777223962620780080784703190447744595561259568772261019375946489162743091583251953125E-122.

    【讨论】:

    • 其他语言也有同样的问题(exploringbinary.com/…),支持@PascalCuoq的结论。例如,在 Java 中,System.out.printf("%.4f\n",12.4155499999999996418864611769 打印 12.4156。(请注意,例如 gcc C 正确:printf("%.4f\n",12.4155499999999996418864611769) 打印12.4155)
    • @aka.nice.: 这不是由于双舍入;这是因为 12.4155499999999996418864611769 转换为单精度为 12.41555023193359375。到 4 个地方,这是正确的 12.4156 。 (与 'f' 是否一样。)
    • @aka.nice:我同意如果你想在 C 中使用浮点数,那么你应该使用 'f' 来确保正确的(单个)二进制舍入。但我不确定你为什么提出浮点数(这个问题是关于双精度的)。
    • @RickRegan 哦,我错误地将“float”列解释为 sybase FLOAT 类型(单精度)。这样就可以解释四舍五入了……我现在要删除这些错误的 cmets。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-25
    • 2014-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-09
    相关资源
    最近更新 更多