我正试图弄清楚如何将货币金额向上舍入到最接近的5美分。以下显示了我的预期结果
1.03 => 1.05
1.051 => 1.10
1.05 => 1.05
1.900001 => 1.10
我需要结果的精度为2(如上所示)。
按照以下建议,我能做的最好的就是这个
BigDecimal amount = new BigDecimal(990.49)
// To round to the nearest .05, multiply by 20, round to the nearest integer, then divide by 20
def result = new BigDecimal(Math.ceil(amount.doubleValue() * 20) / 20)
result.setScale(2, RoundingMode.HALF_UP)
我不相信这是100%犹太人 - 我担心转换到双打时精度可能会丢失。然而,到目前为止,这是我提出的最好的,似乎可以工作。
答案 0 :(得分:56)
使用BigDecimal
没有任何双打(改进了marcolopes的答案):
public static BigDecimal round(BigDecimal value, BigDecimal increment,
RoundingMode roundingMode) {
if (increment.signum() == 0) {
// 0 increment does not make much sense, but prevent division by 0
return value;
} else {
BigDecimal divided = value.divide(increment, 0, roundingMode);
BigDecimal result = divided.multiply(increment);
return result;
}
}
舍入模式例如是RoundingMode.HALF_UP
。对于您的示例,您实际上需要RoundingMode.UP
(bd
是一个只返回new BigDecimal(input)
的助手):
assertEquals(bd("1.05"), round(bd("1.03"), bd("0.05"), RoundingMode.UP));
assertEquals(bd("1.10"), round(bd("1.051"), bd("0.05"), RoundingMode.UP));
assertEquals(bd("1.05"), round(bd("1.05"), bd("0.05"), RoundingMode.UP));
assertEquals(bd("1.95"), round(bd("1.900001"), bd("0.05"), RoundingMode.UP));
另请注意,上一个示例中存在错误(将1.900001舍入到1.10)。
答案 1 :(得分:11)
我会尝试乘以20,四舍五入到最接近的整数,然后除以20.这是一个黑客,但应该得到正确的答案。
答案 2 :(得分:7)
几年前我用Java写了这个:https://github.com/marcolopes/dma/blob/master/org.dma.java/src/org/dma/java/math/BusinessRules.java
/**
* Rounds the number to the nearest<br>
* Numbers can be with or without decimals<br>
*/
public static BigDecimal round(BigDecimal value, BigDecimal rounding, RoundingMode roundingMode){
return rounding.signum()==0 ? value :
(value.divide(rounding,0,roundingMode)).multiply(rounding);
}
/**
* Rounds the number to the nearest<br>
* Numbers can be with or without decimals<br>
* Example: 5, 10 = 10
*<p>
* HALF_UP<br>
* Rounding mode to round towards "nearest neighbor" unless
* both neighbors are equidistant, in which case round up.
* Behaves as for RoundingMode.UP if the discarded fraction is >= 0.5;
* otherwise, behaves as for RoundingMode.DOWN.
* Note that this is the rounding mode commonly taught at school.
*/
public static BigDecimal roundUp(BigDecimal value, BigDecimal rounding){
return round(value, rounding, RoundingMode.HALF_UP);
}
/**
* Rounds the number to the nearest<br>
* Numbers can be with or without decimals<br>
* Example: 5, 10 = 0
*<p>
* HALF_DOWN<br>
* Rounding mode to round towards "nearest neighbor" unless
* both neighbors are equidistant, in which case round down.
* Behaves as for RoundingMode.UP if the discarded fraction is > 0.5;
* otherwise, behaves as for RoundingMode.DOWN.
*/
public static BigDecimal roundDown(BigDecimal value, BigDecimal rounding){
return round(value, rounding, RoundingMode.HALF_DOWN);
}
答案 3 :(得分:3)
这里有一些非常简单的方法,我写的c#总是向上或向下舍入到任何传递的值。
public static Double RoundUpToNearest(Double passednumber, Double roundto)
{
// 105.5 up to nearest 1 = 106
// 105.5 up to nearest 10 = 110
// 105.5 up to nearest 7 = 112
// 105.5 up to nearest 100 = 200
// 105.5 up to nearest 0.2 = 105.6
// 105.5 up to nearest 0.3 = 105.6
//if no rounto then just pass original number back
if (roundto == 0)
{
return passednumber;
}
else
{
return Math.Ceiling(passednumber / roundto) * roundto;
}
}
public static Double RoundDownToNearest(Double passednumber, Double roundto)
{
// 105.5 down to nearest 1 = 105
// 105.5 down to nearest 10 = 100
// 105.5 down to nearest 7 = 105
// 105.5 down to nearest 100 = 100
// 105.5 down to nearest 0.2 = 105.4
// 105.5 down to nearest 0.3 = 105.3
//if no rounto then just pass original number back
if (roundto == 0)
{
return passednumber;
}
else
{
return Math.Floor(passednumber / roundto) * roundto;
}
}
答案 4 :(得分:1)
在Scala中,我做了以下(下面的Java)
import scala.math.BigDecimal.RoundingMode
def toFive(
v: BigDecimal,
digits: Int,
roundType: RoundingMode.Value= RoundingMode.HALF_UP
):BigDecimal = BigDecimal((2*v).setScale(digits-1, roundType).toString)/2
在Java中
import java.math.BigDecimal;
import java.math.RoundingMode;
public static BigDecimal toFive(BigDecimal v){
return new BigDecimal("2").multiply(v).setScale(1, RoundingMode.HALF_UP).divide(new BigDecimal("2"));
}
答案 5 :(得分:0)
根据您的编辑,另一种可能的解决方案是:
BigDecimal twenty = new BigDecimal(20);
BigDecimal amount = new BigDecimal(990.49)
// To round to the nearest .05, multiply by 20, round to the nearest integer, then divide by 20
BigDecimal result = new BigDecimal(amount.multiply(twenty)
.add(new BigDecimal("0.5"))
.toBigInteger()).divide(twenty);
这样做的好处是保证不会失去精确度,尽管它当然可能会慢一些......
scala测试日志:
scala> var twenty = new java.math.BigDecimal(20)
twenty: java.math.BigDecimal = 20
scala> var amount = new java.math.BigDecimal("990.49");
amount: java.math.BigDecimal = 990.49
scala> new BigDecimal(amount.multiply(twenty).add(new BigDecimal("0.5")).toBigInteger()).divide(twenty)
res31: java.math.BigDecimal = 990.5
答案 6 :(得分:0)
您可以使用plain double来执行此操作。
double amount = 990.49;
double rounded = ((double) (long) (amount * 20 + 0.5)) / 20;
编辑:对于负数,您需要减去0.5
答案 7 :(得分:0)
要通过此测试:
assertEquals(bd("1.00"), round(bd("1.00")));
assertEquals(bd("1.00"), round(bd("1.01")));
assertEquals(bd("1.00"), round(bd("1.02")));
assertEquals(bd("1.00"), round(bd("1.024")));
assertEquals(bd("1.05"), round(bd("1.025")));
assertEquals(bd("1.05"), round(bd("1.026")));
assertEquals(bd("1.05"), round(bd("1.049")));
assertEquals(bd("-1.00"), round(bd("-1.00")));
assertEquals(bd("-1.00"), round(bd("-1.01")));
assertEquals(bd("-1.00"), round(bd("-1.02")));
assertEquals(bd("-1.00"), round(bd("-1.024")));
assertEquals(bd("-1.00"), round(bd("-1.0245")));
assertEquals(bd("-1.05"), round(bd("-1.025")));
assertEquals(bd("-1.05"), round(bd("-1.026")));
assertEquals(bd("-1.05"), round(bd("-1.049")));
更改ROUND_UP
中的ROUND_HALF_UP
:
private static final BigDecimal INCREMENT_INVERTED = new BigDecimal("20");
public BigDecimal round(BigDecimal toRound) {
BigDecimal divided = toRound.multiply(INCREMENT_INVERTED)
.setScale(0, BigDecimal.ROUND_HALF_UP);
BigDecimal result = divided.divide(INCREMENT_INVERTED)
.setScale(2, BigDecimal.ROUND_HALF_UP);
return result;
}
答案 8 :(得分:0)
import javax.swing.*;
import java.awt.event.*;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class KaraokeMachine extends JFrame implements ActionListener
{
ClassLoader Idr = this.getClass().getClassLoader();
java.applet.AudioClip everythingIsAwesome = JApplet.newAudioClip( Idr.getResource( "everything is awesome.wav" ) );
JLabel lbl1 = new JLabel( "" );
JButton btn = new JButton( "Play" );
JPanel pnl = new JPanel();
final Executor executor = Executors.newCachedThreadPool();
public KaraokeMachine()
{
super( "Karaoke" );
setSize( 520, 280 );
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
pnl.add( lbl1 );
pnl.add( btn );
btn.addActionListener( this );
add( pnl ); setVisible( true );
}
public void actionPerformed( ActionEvent event )
{
if ( event.getSource() == btn )
{
SwingWorker<Void, String> worker = new SwingWorker<Void, String>()
{
@Override
protected Void doInBackground() throws Exception
{
everythingIsAwesome.play();
this.publish("Everything");
Thread.sleep( 600 );
this.publish("Everything is");
Thread.sleep( 400 );
this.publish("Everything is Awesome!");
Thread.sleep( 2000 );
this.publish("Everything");
Thread.sleep( 600 );
this.publish("Everything is");
Thread.sleep( 400 );
this.publish("Everything is cool");
Thread.sleep( 400 );
this.publish("Everything is cool when");
Thread.sleep( 400 );
this.publish("Everything is cool when you're");
Thread.sleep( 400 );
this.publish("Everything is cool when you're part");
Thread.sleep( 150 );
this.publish("Everything is cool when you're part of");
Thread.sleep( 150 );
this.publish("Everything is cool when you're part of a");
Thread.sleep( 150 );
this.publish("Everything is cool when you're part of a team");
Thread.sleep( 1000 );
this.publish("Everything");
Thread.sleep( 600 );
this.publish("Everything is");
Thread.sleep( 400 );
this.publish("Everything is Awesome!");
Thread.sleep( 1500 );
this.publish("When");
Thread.sleep( 300 );
this.publish("When you're");
Thread.sleep( 300 );
this.publish("When you're livin'");
Thread.sleep( 300 );
this.publish("When you're livin' in");
Thread.sleep( 300 );
this.publish("When you're livin' in a");
Thread.sleep( 300 );
this.publish("When you're livin' in a dream!");
Thread.sleep( 300 );
return null;
}
@Override
protected void process( List<String> res )
{
for(String text : res)
{
lbl1.setText(text);
}
}
};
executor.execute(worker);
}
}
public static void main( String[] args )
{
KaraokeMachine karaoke = new KaraokeMachine();
}
请注意,这与John's基本相同。
答案 9 :(得分:0)
\s
答案 10 :(得分:-1)
Tom有正确的想法,但您需要使用BigDecimal方法,因为您表面上使用的是BigDecimal,因为您的值不适合原始数据类型。类似的东西:
BigDecimal num = new BigDecimal(0.23);
BigDecimal twenty = new BigDecimal(20);
//Might want to use RoundingMode.UP instead,
//depending on desired behavior for negative values of num.
BigDecimal numTimesTwenty = num.multiply(twenty, new MathContext(0, RoundingMode.CEILING));
BigDecimal numRoundedUpToNearestFiveCents
= numTimesTwenty.divide(twenty, new MathContext(2, RoundingMode.UNNECESSARY));