CURRENCY - 仅当它有超过 2 个小数位时才舍入双精度值
CURRENCY - Round double value ONLY if it has more than 2 decimal places
我正在尝试拆分账单,并且需要计算如果账单被平均拆分的话每个人会欠多少钱。我知道一笔金额将与其余金额不同,以弥补损失的美分。
假设 3 个人尝试分摊 200 的账单。200 / 3 是 66.6666666667。我打算做的是向前两个人收取 66.67 的费用,最后一个幸运地支付了 66.66 的账单。
目前,我有这个:
private String calculateAmountToPay(String noOfParticipants, String owed) {
double amountOwed = Double.parseDouble(owed);
int noOfMembers = Integer.parseInt(noOfParticipants);
DecimalFormat amountFormat = new DecimalFormat("#.##");
amountFormat.setRoundingMode(RoundingMode.CEILING);
return amountFormat.format((amountOwed/(double)noOfMembers) / 100);
}
但这总是 return66.67。有没有一种方法可以让它只在有大于 2 位小数的数字时四舍五入,如果不是,它保持在 66.66,例如?
也许我处理这个问题的方式不对。我知道处理货币可能很挑剔。
您可以在半舍入模式下使用 BigDecimal:
private String calculateAmountToPay(String noOfParticipants, String owed) {
double amountOwed = Double.parseDouble(owed);
int noOfMembers = Integer.parseInt(noOfParticipants);
BigDecimal amount= new BigDecimal((amountOwed / (double) noOfMembers) / 100);
return amount.setScale(2, RoundingMode.HALF_UP).toString();
}
您可以使用基本原语进行所有计算,将所有内容转换为分(精度为 2 位小数),并将剩余的分分给一部分成员,无需额外 sdks/math 使其过于复杂操纵。以下是使用这些建议完全解决此问题的工作示例:
public class AmountDivider {
private int totalMembers, luckies, unluckies;
private double totalAmount, amountPerLucky, amountPerUnlucky;
public AmountDivider(int numMembers, double amountOwed) {
totalMembers = numMembers;
totalAmount = amountOwed;
double centsOwed = amountOwed * 100;
int centsPerMember = (int)(centsOwed / totalMembers);
int centsLeft = (int)centsOwed - centsPerMember * totalMembers;
luckies = totalMembers - centsLeft;
amountPerLucky = centsPerMember / 100.0;
unluckies = centsLeft;
amountPerUnlucky = (centsPerMember + 1) / 100.0;
}
public String toString() {
String luckiesStr = String.format("%d lucky persons will pay %.2f", luckies, amountPerLucky);
String unluckiesStr = String.format("%d unlucky persons will pay %.2f", unluckies, amountPerUnlucky);
return String.format("For amount %f divided among %d: \n%s\n%s\n",
totalAmount, totalMembers, luckiesStr, unluckiesStr);
}
public static void main(String[] args) {
System.out.println(new AmountDivider(3, 200));
System.out.println(new AmountDivider(17, 365.99));
}
}
希望对您有所帮助。
在考虑算术之前,您需要知道 double
不是 适合与货币一起使用的数据类型,因为它 不精确。因此,停止使用浮点类型(例如 double
)作为数量 dollars 的数据类型,并开始使用精确类型(例如 long
)作为cents.
数量的数据类型
然后进行计算的步骤是立即将所有内容四舍五入转换为美分:
double amountOwed = ...;
int noOfMembers = ...;
long centsOwed = Math.round(amountOwed * 100);
long portionCents = Math.round(amountOwed * 100 / noOfMembers);
long errorCents = portionCents * noOfMembers - centsOwed;
这是处理错误的一种方法:
long lastPortionCents = portionCents - errorCents;
但误差可能超过 1 美分,因此更好的解决方案是通过从第一个(或最后一个,或随机选择)errorCents
位食客。
剩下的解决方案就是关于撕裂上面的内容,我留给 reader。
附带说明一下,使用美分是银行传输金额的方式(至少对于 EFTPOS 而言)。
关于基本软件设计,我会创建一个单独的方法,它接受整数美分和人数作为其参数,returns 一个 "split" 数量的数组。这样做不仅会让你的代码更容易阅读,而且会划分算术运算,从而使许多简单的测试更容易编写,所以你可以知道你已经涵盖了你能想到的所有边缘情况。
我正在尝试拆分账单,并且需要计算如果账单被平均拆分的话每个人会欠多少钱。我知道一笔金额将与其余金额不同,以弥补损失的美分。
假设 3 个人尝试分摊 200 的账单。200 / 3 是 66.6666666667。我打算做的是向前两个人收取 66.67 的费用,最后一个幸运地支付了 66.66 的账单。
目前,我有这个:
private String calculateAmountToPay(String noOfParticipants, String owed) {
double amountOwed = Double.parseDouble(owed);
int noOfMembers = Integer.parseInt(noOfParticipants);
DecimalFormat amountFormat = new DecimalFormat("#.##");
amountFormat.setRoundingMode(RoundingMode.CEILING);
return amountFormat.format((amountOwed/(double)noOfMembers) / 100);
}
但这总是 return66.67。有没有一种方法可以让它只在有大于 2 位小数的数字时四舍五入,如果不是,它保持在 66.66,例如?
也许我处理这个问题的方式不对。我知道处理货币可能很挑剔。
您可以在半舍入模式下使用 BigDecimal:
private String calculateAmountToPay(String noOfParticipants, String owed) {
double amountOwed = Double.parseDouble(owed);
int noOfMembers = Integer.parseInt(noOfParticipants);
BigDecimal amount= new BigDecimal((amountOwed / (double) noOfMembers) / 100);
return amount.setScale(2, RoundingMode.HALF_UP).toString();
}
您可以使用基本原语进行所有计算,将所有内容转换为分(精度为 2 位小数),并将剩余的分分给一部分成员,无需额外 sdks/math 使其过于复杂操纵。以下是使用这些建议完全解决此问题的工作示例:
public class AmountDivider {
private int totalMembers, luckies, unluckies;
private double totalAmount, amountPerLucky, amountPerUnlucky;
public AmountDivider(int numMembers, double amountOwed) {
totalMembers = numMembers;
totalAmount = amountOwed;
double centsOwed = amountOwed * 100;
int centsPerMember = (int)(centsOwed / totalMembers);
int centsLeft = (int)centsOwed - centsPerMember * totalMembers;
luckies = totalMembers - centsLeft;
amountPerLucky = centsPerMember / 100.0;
unluckies = centsLeft;
amountPerUnlucky = (centsPerMember + 1) / 100.0;
}
public String toString() {
String luckiesStr = String.format("%d lucky persons will pay %.2f", luckies, amountPerLucky);
String unluckiesStr = String.format("%d unlucky persons will pay %.2f", unluckies, amountPerUnlucky);
return String.format("For amount %f divided among %d: \n%s\n%s\n",
totalAmount, totalMembers, luckiesStr, unluckiesStr);
}
public static void main(String[] args) {
System.out.println(new AmountDivider(3, 200));
System.out.println(new AmountDivider(17, 365.99));
}
}
希望对您有所帮助。
在考虑算术之前,您需要知道 double
不是 适合与货币一起使用的数据类型,因为它 不精确。因此,停止使用浮点类型(例如 double
)作为数量 dollars 的数据类型,并开始使用精确类型(例如 long
)作为cents.
然后进行计算的步骤是立即将所有内容四舍五入转换为美分:
double amountOwed = ...;
int noOfMembers = ...;
long centsOwed = Math.round(amountOwed * 100);
long portionCents = Math.round(amountOwed * 100 / noOfMembers);
long errorCents = portionCents * noOfMembers - centsOwed;
这是处理错误的一种方法:
long lastPortionCents = portionCents - errorCents;
但误差可能超过 1 美分,因此更好的解决方案是通过从第一个(或最后一个,或随机选择)errorCents
位食客。
剩下的解决方案就是关于撕裂上面的内容,我留给 reader。
附带说明一下,使用美分是银行传输金额的方式(至少对于 EFTPOS 而言)。
关于基本软件设计,我会创建一个单独的方法,它接受整数美分和人数作为其参数,returns 一个 "split" 数量的数组。这样做不仅会让你的代码更容易阅读,而且会划分算术运算,从而使许多简单的测试更容易编写,所以你可以知道你已经涵盖了你能想到的所有边缘情况。