sybase 15.7浮点数到数字舍入错误

Mik*_*eed 4 floating-point sybase-ase

任何人都可以解释以下内容,这对我来说只是一个bug:

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

12.4156
Run Code Online (Sandbox Code Playgroud)

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

我认为这是错误的,还是我生气了?

Pas*_*uoq 6

在Sybase中,从双精度到十进制的转换可能会遇到双舍入错误.

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

然后,由于你在点之后要求4个十进制数字,中间的十进制表示将四舍五入到它,在tie-go-up或tie-go-to-nearest-even下.两者都是错的,因为第一轮舍入已经失去了一些关键信息(即原始数字略低于12.41555,不完全是这样).

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

笔记:

  1. 作为参考,我们所讨论的双精度数的精确值是12.415549999999999641886461176909506320953369140625.

  2. 根据Mark Dickinson对这个问题的回答,对于第一次转换,转换超过第二次舍入所需的超过20位十进制数字将使结果安全,不会受到"双舍入"的任何明显影响.在你的问题的数量是连续花枝招展的在双的最大数量一个很好的候选人,但在马克的2.12818792307269553358078502102171540639252016258831784842556110831434197718043638405555406495645619729155240037555858106390933161420388023706431461384056688295540725831155392678607931808851292893574214797681879999999999999999999941026584542575391157788777223962620780080784703190447744595561259568772261019375946489162743091583251953125E-122的前相形见绌.

  • 其他语言也有同样的问题(http://www.exploringbinary.com/inconsistent-rounding-of-printed-floating-point-numbers/),它支持@PascalCuoq的结论.例如,在Java中,System.out.printf("%.4f \n",12.4155499999999996418864611769打印12.4156.(请注意,gcc C,例如,正确:printf("%.4f \n",12.4155499999999996418864611769)打印12.4155) (2认同)
  • @ aka.nice:这不是因为双舍入; 这是因为12.4155499999999996418864611769转换为单精度为12.41555023193359375.到4个地方,这是正确的12.4156.(与'f'的工作方式相同或不同.) (2认同)