【问题标题】:Decimal Truncation/Rounding difference in console and though JDBC控制台和 JDBC 中的十进制截断/舍入差异
【发布时间】:2013-02-20 07:07:09
【问题描述】:

我在将双精度值插入具有小数精度的数据库表时遇到问题。我正在使用 MS SQL Server 版本 10.0.4000 下面是一个小数列有 4 个小数位的示例表。

create table test (
test decimal (18,4))

当我通过 MSSQL 控制台插入值“36.78675”时,它会被四舍五入为 36.7868,因为该字段只有 4 位小数。这可以。

DECLARE @T DECIMAL(18, 5)

SET @T = 36.78675

insert into test values(@T)

select * from test

但是当我通过我的 java 代码(MS SQL JDBC 驱动程序)执行等效插入(使用准备好的语句)时,存储在表中的数据是36.7867。如果我有一个像 36.786750001 这样的值,控制台和 JDBC 都会四舍五入到 36.7868。 我使用的 java 对象是 double 的。我用双值调用 setDouble() 。在这里它会自动选择数据类型。但是还有另一种 JDBC 方法,它采用对象和数据类型。使用它,我用 DECIMAL 和 FLOAT 类型进行了测试。所有人都给出了相同的结果。我什至将 jdbc 驱动程序更改为 I-net。也有同样的结果。

有人知道为什么通过驱动程序进行舍入的工作方式不同吗?是否有任何设置可以让它像控制台一样工作?

【问题讨论】:

  • 说“SQL Server 控制台”,是指SQL Server Management Studio吗?

标签: java sql-server tsql jdbc rounding-error


【解决方案1】:

这是因为二进制浮点的性质,这就是您在 double 中使用的(在 Java 中)。

double 最接近 36.7875 的准确值是

36.7867499999999978399500832892954349517822265625

将向下舍入为 36.7867。而最接近 36.78750001 的double精确值是

36.786750000099999624580959789454936981201171875

四舍五入到 36.7878。这就是你得到这种行为的原因。控制台可能会将输入视为十进制数,而不是转换为二进制浮点数。

如果精确的十进制数字对您很重要,您可能不应该使用二进制浮点类型 - 改用 BigDecimal

您应该真正考虑一下您的价值代表什么。如果它是一个物理连续值,例如身高、长度或体重,那么使用double 可能毕竟是合适的——但你不应该对这样的情况感到困惑。如果它是具有离散(基于十进制)值(例如货币值)的人工构造,那么您绝对应该使用BigDecimal,或者简单地缩放一个整数。

【讨论】:

  • 感谢您提供详细信息。除了 percision,我的问题是 java roding 和数据库的默认截断/舍入不一致。当值为“36.78675”时,Java 舍入给出 36.7868,但如果在存储前未专门舍入该值,则数据库中存储的值为“36.7867”。我需要检索数据并与 java 代码中的值进行比较。在这里,当我将 36.7868(java 代码)与 36.7867(数据库)进行比较时,我不会得到匹配。
  • @BijuSanakan:我的意思是double 变量的值不能为 36.78675。这是不可能的。这就像试图用十进制表示写下“三分之一”的确切值。同样,如果“36.78675”的确切值对您很重要,您应该使用BigDecimal
  • 我同意你的看法。但我的问题是为什么它在 java 和 mssql 中对相同的数字 36.78675 进行不同的舍入。 public static void roundUnits(double v1) { return java.util.Math.round(v1 * 10000)/10000; } 双 d = 36.78675; System.out.println(roundUnits(d));当我调用上述代码时,它会打印出 36.7868。我期待 MSSQL 有同样的行为。但在 MSSQL 中,它被存储为 36.7867
  • @BijuSanakan:因为大概 SQL Server 控制台没有首先将其转换为 double。它将它 just 视为十进制输入。在您的 roundUnits 方法中,您将乘以和除以 10000,这可能会以各种方式影响数据 - 您必须查看确切样本输入的结果是什么去理解它。但这里的根本区别在于您是以 36.78675(如果您使用基于十进制的表示)还是 36.7867499999999978399500832892954349517822265625(如果您使用 64 位二进制浮点表示)开头。
猜你喜欢
  • 2010-09-24
  • 2011-06-22
  • 1970-01-01
  • 1970-01-01
  • 2016-04-22
  • 1970-01-01
  • 1970-01-01
  • 2016-12-19
  • 1970-01-01
相关资源
最近更新 更多