--短期解决方案--

感谢您提供的所有信息丰富的回复@PetrJaneček@Matt为我指出了正确的方向.我同意我必须温习一下我对浮点运算的理解;但是使用valueOf调用构造函数与double的规范字符串表示的区别解决了我的问题.

private static Double sampleRound(Double value, int places) {
    BigDecimal bd1 = BigDecimal.valueOf(value);
    bd1 = bd1.setScale(places, RoundingMode.HALF_UP);

    return bd1.doubleValue();
}

由@PetrJaneček和有用的视频提供:

youtu.be/wbp-3BJWsU8?t=246

--原始问题--

关于舍入,我遇到了一个非常奇怪的问题,我只是想知道我错在哪里.

功能是:

private static Double sampleRound(Double value, int places) {
    BigDecimal bd1 = new BigDecimal(value);
    bd1 = bd1.setScale(places, RoundingMode.HALF_UP);
    
    return bd1.doubleValue();
}

如果我传递值"1942.945",我希望它输出"1942.95",但我得到的是"1942.94".然而,如果我通过"1942.9451",我会得到"1942.95".好吧,那么让我们假设我将这个逻辑保留到小数点后3位.因此,如果我通过"1942.9445",我期望得到"1942.944",但我得到的是"1942.945",如何以及为什么?我觉得这个逻辑似乎不正确?

sampleRound(1942.945, 2) -> 1942.94

[Does NOT make sense, should be 1942.95]

sampleRound(1942.9450000000001, 2)-> 1942.95

*编辑:我也通过了这个(1个额外的零),我再次理解了数据类型及其约束,我想我要说的是分数.005不被视为半价>=5: 根据java文档"丢弃的分数是≥ 0.5;"它本质上是将其视为>0.5而不是>=0.5*

sampleRound(1942.94500000000001, 2) -> 1942.94

[Then this should be equivalent to the top]

好的,但很好,我可以处理上述逻辑,但只要我做3位小数:

sampleRound(1942.9445, 3) -> 1942.945

[Does NOT make sense, in accordance with top logic should be 19423.944].

我希望通过描述可以理解,但我被难住了?

当做

推荐答案

正如@PetrJaneček在 comments 中所建议的,您可以通过使用BigDecimal.valueOf来绕过这个问题,BigDecimal.valueOf将"使用double.toString(double)方法提供的double的规范字符串表示"创建一个bigdecime.

BigDecimal构造函数new BigDecimal(double)根据提供的双精度的精确值创建一个BigDecimal.

double v =  1942.945;
System.out.println( Double.toString(v) );
System.out.println( new BigDecimal(v) );
System.out.println( BigDecimal.valueOf(v) );

1942.945
1942.944999999999936335370875895023345947265625
1942.945

我们看到的是,第一个"规范字符串"v,这是您所期望的,但确切值不是"1942.945",而是稍小一些.我们可以看到,当我们使用BigDecimal构造函数并得到确切的值时.

对于其余的示例,我们只需要看一下精确的表示.

System.out.println( new BigDecimal( 1942.9450000000001 ) );

1942.94500000000016370904631912708282470703125

System.out.println( new BigDecimal( 1942.94500000000001 ) );

1942.944999999999936335370875895023345947265625

System.out.println( new BigDecimal( 1942.9445 ) );

1942.94450000000006184563972055912017822265625

从这一点上,我想很清楚为什么你的舍入行为是这样的.

Java相关问答推荐

BiPredicate和如何使用它

如何在Android上获取来电信息

方法没有用正确的值填充数组—而是将数组保留为null,'

Character::Emoji不支持带数字的字符吗?

通过合并Akka Streams中的多个慢源保持订购

AssertJ Java:多条件断言

在Java Swing Paint应用程序中捕获快速鼠标移动时遇到困难

如何调整工作时间日历中的时间

由于 list 中的权限错误,Android未生成

使用Room Database删除Jetpack合成中的所有项目后,UI未重新合成

使用OAuth 2.0资源服务器JWT时的授权(授权)问题

为什么我的回收视图会显示重复的列表?

buildDir:File!&#的getter解决方案是什么?39.被抛弃

当我在Java中有一个Synchronized块来递增int时,必须声明一个变量Volatile吗?

如何调整JButton的大小以适应图标?

在Java中将.GRF转换为图像文件

在单例类上获取Java锁,了解原因

HBox内部的左对齐按钮(如果重要的话,在页码内)

当我try 返回可选时,Mock无法正常工作

为什么Java编译器为没有参数的方法(getter方法)创建桥接方法