Java ORM/DSL中返回的浮点类型
声明“此数据类型[double]不应用于精确值,如货币。”ORM/DSL为存储用于计算货币金额的值的数据库列返回浮点数这一事实是否存在问题?我在使用QueryDSL,我在处理钱的问题。QueryDSL将为精度高达16的任何数字返回一个Java ORM/DSL中返回的浮点类型,java,oracle,hibernate,floating-point,querydsl,Java,Oracle,Hibernate,Floating Point,Querydsl,声明“此数据类型[double]不应用于精确值,如货币。”ORM/DSL为存储用于计算货币金额的值的数据库列返回浮点数这一事实是否存在问题?我在使用QueryDSL,我在处理钱的问题。QueryDSL将为精度高达16的任何数字返回一个Double,然后返回一个BigDecimal。这让我担心,因为我知道浮点运算不适合于货币计算 从那时起,我开始相信冬眠也会做同样的事情;请参见oraclealtaneol。为什么它使用的是Double而不是BigDecimal?检索双精度并构造大十进制是否安全,或
Double
,然后返回一个BigDecimal
。这让我担心,因为我知道浮点运算不适合于货币计算
从那时起,我开始相信冬眠也会做同样的事情;请参见
oraclealtaneol
。为什么它使用的是Double
而不是BigDecimal
?检索双精度
并构造大十进制
是否安全,或者精度小于16的数字是否有可能被错误表示?是否只有在执行算术运算时,Double
才会出现浮点问题,或者是否存在无法准确初始化的值?使用浮点数字存储货币确实是一个难题。浮点数可以近似运算结果,但这不是处理货币时需要的结果
以数据库可移植的方式修复它的最简单方法是简单地存储美分。这是金融业务中处理货币业务的一种方式。请注意,大多数数据库都使用舍入算法,因此请确保该算法适合您的上下文
说到钱,你应该经常问当地的会计师,尤其是四舍五入部分。安全总比抱歉好
现在回到你的问题:
BigDecimal
。因此,如果您可以保证数据库值在转换为java Double时不会丢失任何小数,那么可以从中创建BigDecimal
。当对数据库加载的值应用算术运算时,使用bigdecime
是值得的经过深思熟虑,我必须得出结论,我自己的问题的答案是: ORM/DSL为存储用于计算货币金额的值的数据库列返回浮点数这一事实是一个问题吗 简言之,答案是肯定的。请继续读下去 检索Double并构造BigDecimal是否安全,或者是否有可能错误表示精度小于16的数字 以下示例中,精度小于16位十进制数字的数字表示不正确
BigDecimal foo = new BigDecimal(1000.1d);
foo
的BigDecimal
值为1000.100000000002273767544323205947775765625。1000.1的精度为1,与BigDecimal
值的精度14不符
是否只有在执行算术运算时,Double才会出现浮点问题,或者是否存在无法准确初始化的值
根据上述示例,存在无法准确初始化的值。正如明确指出的,“这种数据类型[float/double]永远不应该用于精确的值,比如货币。为此,您将需要使用java.math.BigDecimal类。”
有趣的是,调用BigDecimal.valueOf(someDouble)
一开始似乎是为了神奇地解决问题,但当意识到它调用了Double.toString()
之后,读起来很明显,这也不适用于精确的值
总之,在处理精确值时,浮点数永远不合适。因此,在我看来,ORMs/dsl应该映射到BigDecimal
,除非另有规定,因为大多数数据库使用都会涉及精确值的计算
更新:
基于这一结论,我提出了QueryDSL。它不仅涉及算术运算,还涉及纯读写。 Oracle
NUMBER
和BigDecimal
都使用十进制基数。所以,当您从数据库中读取数字,然后将其存储回数据库时,您可以确定,写入的数字是相同的。(除非超过Oracle的38位限制)
如果您将
数字
转换为二进制基数(双精度
),然后将其转换回十进制,则可能会出现问题。而且这个操作必须要慢得多。的问题、评论和回答中似乎提到了几个问题。我收集并解释了其中的一些