【问题标题】:SQL Server Strange Ceiling() behaviorSQL Server 奇怪的 Ceiling() 行为
【发布时间】:2014-10-02 16:35:39
【问题描述】:

谁能解释 SQL Server 中的以下结果?我被难住了。

declare @mynum float = 8.31

select ceiling( @mynum*100)

831 中的结果

declare @mynum float = 8.21

select ceiling( @mynum*100)

822 中的结果

我已经测试了一系列数字(SQL Server 2012)。一些增加,而另一些保持不变。我不明白为什么天花板会以不同的方式对待其中一些。从float 更改为decimal(18,5) 似乎可以解决问题,但我担心这样做可能会产生其他影响。任何解释都会有所帮助。

【问题讨论】:

  • 你为什么使用浮点数?我不知道切换到十进制会产生什么影响,除非您必须输入更多内容并且具有更可预测的准确性。去做就对了。请参阅this article、this article、this article 和 this Q & A。
  • 感谢文章。

标签: sql sql-server sql-server-2012


【解决方案1】:

我认为这称为浮点精度。您几乎可以在所有编程语言和数据库中找到它。这是因为数据仅以某种精度存储,实际上您设置为8.31 的可能不是8.31,而是8.31631312381813,当将它与 ceil 相乘时,可能会导致出现不同的值。

在SQL server documentation page ,您可以阅读:

用于浮点数值数据的近似数数据类型。浮点数据是近似的;因此,并非数据类型范围内的所有值都可以准确表示。

在其他数据库系统中也存在同样的问题。例如mysql website,您可以阅读:

浮点数有时会引起混淆,因为它们是近似值而不是存储为精确值。 SQL 语句中写入的浮点值可能与内部表示的值不同。尝试在比较中将浮点值视为精确可能会导致问题。它们还受平台或实现依赖关系的影响。 FLOAT 和 DOUBLE 数据类型受这些问题的影响。对于 DECIMAL 列,MySQL 执行精度为 65 位十进制数字的操作,这应该可以解决最常见的不准确问题。

【讨论】:

  • @Lasse 不同的数字将由不同的浮点数表示。如果 8.31 实际上被表示为 8.3100000000000001,那么乘以它就是 831.000000000001,那么 CEILING(831.0000000000001) 是什么? 832. 如果 8.21 被表示为 8.209999999999 ... 等等。
  • 您可能想要来自the SQL Server documentation 的引用,而不是来自 MySQL 文档的任何内容:Approximate-number data types for use with floating point numeric data. Floating point data is approximate; therefore, not all values in the data type range can be represented exactly.
  • @Lasse 太好了,如果您总是处理值 100。
  • @Lasse 您认为问题中可能存在拼写错误吗?他们说他们测试了一大堆价值观。你能看到过去吗?所描绘的问题是一个值 (8.31) 按预期工作,并且不四舍五入,而另一个值 (8.21) 工作方式不同,并且四舍五入。不管他们错误地陈述了实际的显式输出,您都可以看到行为有所不同,是吗?
  • (我不认为 OP 关心(或应该关心)它在 MySQL 中的工作方式。你能回答 SQL Server 的问题吗?)
【解决方案2】:

浮点数并非 100% 准确。就像 Marcin Nabiałek 写的那样,你看到的 8.31 可能由其他东西表示,比如 8.310000000001。请参阅here 了解有关浮点精度问题的一些有趣的阅读。

解决方案是不要使用浮点数据类型,除非你真的必须这样做。您应该使用 DECIMAL 或 MONEY 数据类型。

如果您真的必须使用浮点数据类型,那么您可以在每个 floor 之前添加或减去一个小值(准确度阈值或 epsilon) , ceiling 或比较操作以获得您想要的精度。如果您有很多浮点运算,那么编写自己的floating point comparison functions 可能是值得的。

【讨论】:

    猜你喜欢
    • 2013-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多