首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在ORM / DSL中返回的浮点类型

在ORM / DSL中返回的浮点类型
EN

Stack Overflow用户
提问于 2015-02-06 17:16:14
回答 4查看 667关注 0票数 4

Java™教程声明“此数据类型不应用于精确值(如货币)”。ORM / DSL返回用于存储用于计算货币金额的值的数据库列的浮点数是否是一个问题?我用的是QueryDSL,我在处理钱。QueryDSL将返回精度可达16的任意数字的Double,并在此之后返回BigDecimal。这让我担心,因为我知道浮点算法不适合货币计算。

这个QueryDSL问题中,我被引导相信Hibernate也会做同样的事情;参见OracleDialect。为什么它使用Double而不是BigDecimal?检索Double并构造BigDecimal是安全的,还是一个精度小于16的数字可能被错误地表示?是只有在执行算术运算时,Double才会出现浮点问题,还是存在无法精确初始化的值?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2015-02-12 06:59:28

罗伯特·贝恩的问题、评论和答案中似乎提到了几个问题。我收集并翻译了其中的一些。

  1. 用双倍来存储精确的值安全吗?

是的,只要有效位数(精度)足够小.

来自维基百科

如果一个十进制字符串的有效位数最多为15个,则转换为IEEE754双精度表示,然后将其转换回具有相同有效位数的字符串,则最终字符串应与原始字符串匹配。

代码语言:javascript
复制
-  But `new BigDecimal(1000.1d)` has the value 1000.1000000000000227373675443232059478759765625, why not 1000.1?

在上面的引号中,我增加了强调--当从双倍转换时,必须指定有效数字的数目。

new BigDecimal(1000.1d, new MathContext(15))

  1. 对于精确值的任意算术,使用双数安全吗?

否,计算中使用的每一个中间值都会引入额外的错误。

使用double来存储确切的值应该被看作是一种优化。它带来的风险是,如果不小心,就可能失去精确性。使用BigDecimal不太可能带来意想不到的后果,这应该是您的默认选择。

  1. QueryDSL返回精确值的双倍是正确的吗?

这不一定是不正确的,但可能是不可取的。我建议你和QueryDSL开发人员联系.但我看到你已经提高了问题,他们打算改变这种行为。

票数 1
EN

Stack Overflow用户

发布于 2015-02-08 21:52:16

使用浮点数来存储货币确实是一个馊主意。浮点数可以近似于运算结果,但在处理金钱时,这不是你想要的。

用数据库可移植的方式修复它的最简单的方法就是简单地存储美分。这是在金融业务中处理货币操作的一种方式。请注意,大多数数据库都使用半途而废舍入算法,因此确保这在您的上下文中是合适的。

说到钱,你应该经常问当地的会计,特别是关于四舍五入的问题。安全总比抱歉好。

现在回到你的问题:

  1. 检索该双值并构造BigDecimal是安全的,还是一个精度小于16的数字可能被错误地表示?

这是一个安全的操作,只要您的数据库最多使用16位精度。如果它使用更高的精度,则需要覆盖OracleDialect和

  1. 是只有在执行算术运算时才会出现浮点问题,还是有些值不能被精确初始化?

在执行算术运算时,您必须始终考虑货币四舍五入,这也适用于BigDecimal。因此,如果您能够保证数据库值在被转换为java双值时不会丢失任何十进制值,那么您可以从它创建一个BigDecimal。在对数据库加载的值应用算术操作时,使用BigDecimal是有回报的。

至于16的阈值,根据维基的说法

该指数的11位宽度允许用10−308-10308之间的十进制指数表示数字,具有完整的15-17小数位精度。通过降低精度,低于正常的表示允许小于10−323的值。

票数 3
EN

Stack Overflow用户

发布于 2015-02-10 14:26:24

经过深思熟虑,我必须得出结论,我自己问题的答案是:

ORM / DSL返回用于存储用于计算货币金额的值的数据库列的浮点数是否是一个问题?

简单地说,是的。请继续读。

检索该双值并构造BigDecimal是安全的,还是一个精度小于16的数字可能被错误地表示?

在下面的示例中,精度小于16小数位的数字被错误地表示。

代码语言:javascript
复制
BigDecimal foo = new BigDecimal(1000.1d);

1000.1000000000000227373675443232059478759765625.是fooBigDecimal值。1000.1的精度为1,并且正在从BigDecimal值的精度14中被错误地表示。

是只有在执行算术运算时才会出现浮点问题,还是有些值不能被精确初始化?

正如上面的例子所示,有些值不能被精确地初始化。正如Java™教程明确指出的那样,“此数据类型浮点/双不应用于精确值,如货币。为此,您将需要使用java.math.BigDecimal类。”

有趣的是,最初调用BigDecimal.valueOf(someDouble)似乎是为了神奇地解决问题,但当意识到它调用了Double.toString(),然后读取[经]文件时,很明显,这也不适合精确的值。

总之,在处理精确值时,浮点数字是不合适的。因此,在我看来,除非另有规定,否则ORM/DSL应该映射到BigDecimal,因为大多数数据库的使用将涉及精确值的计算。

更新:

基于这一结论,我提出了本期与QueryDSL。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28371179

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档