Java ORM/DSL中返回的浮点类型

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]不应用于精确值,如货币。”ORM/DSL为存储用于计算货币金额的值的数据库列返回浮点数这一事实是否存在问题?我在使用QueryDSL,我在处理钱的问题。QueryDSL将为精度高达16的任何数字返回一个
Double
,然后返回一个
BigDecimal
。这让我担心,因为我知道浮点运算不适合于货币计算


从那时起,我开始相信冬眠也会做同样的事情;请参见
oraclealtaneol
。为什么它使用的是
Double
而不是
BigDecimal
?检索
双精度
并构造
大十进制
是否安全,或者精度小于16的数字是否有可能被错误表示?是否只有在执行算术运算时,
Double
才会出现浮点问题,或者是否存在无法准确初始化的值?

使用浮点数字存储货币确实是一个难题。浮点数可以近似运算结果,但这不是处理货币时需要的结果

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

说到钱,你应该经常问当地的会计师,尤其是四舍五入部分。安全总比抱歉好

现在回到你的问题:

  • 检索Double并构造BigDecimal安全吗 一个精度小于16的数字有可能是 错误地表示

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

  • 是否只有在执行算术运算时,双精度计数器才能 是否存在浮点问题,或者是否存在无法访问的值 准确地初始化

    在执行算术运算时,您必须始终考虑货币舍入,这也适用于
    BigDecimal
    。因此,如果您可以保证数据库值在转换为java Double时不会丢失任何小数,那么可以从中创建
    BigDecimal
    。当对数据库加载的值应用算术运算时,使用
    bigdecime
    是值得的

  • 对于16的阈值,根据:

    指数的11位宽度允许表示数字 十进制指数在10和10之间−308和10308,以及完整的15–17 小数位数精度。通过降低精度,低于正常值 表示允许小于10的值−323


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

    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位限制)


    如果您将
    数字
    转换为二进制基数(
    双精度
    ),然后将其转换回十进制,则可能会出现问题。而且这个操作必须要慢得多。

    的问题、评论和回答中似乎提到了几个问题。我收集并解释了其中的一些

  • 使用double存储精确值是否安全

    可以,前提是有效位数(精度)足够小

    如果将最多有15个有效数字的十进制字符串转换为IEEE 754双精度表示,然后再转换回具有相同有效数字数的字符串,则f