Java中的货币转换器具有精度和浓缩问题
Posted
技术标签:
【中文标题】Java中的货币转换器具有精度和浓缩问题【英文标题】:Currency Converter in Java having precision and condensing issues 【发布时间】:2018-10-26 01:58:08 【问题描述】:我得到了一个用 Java 编写的作业。
我们将开发一个货币转换应用程序,该应用程序询问他们要转换的货币、所述货币的数量以及他们希望转换成的货币。
该指令指出我们应该包括 4 种货币来转换/转换。
我很早就完成了作业,我去给我的教授看,她注意到了一些问题。她喜欢代码的组织性和清晰性,但她认为我可以将其缩小一点,并解决我在小数精度方面遇到的问题。
关于缩短它的时间,她的主要论点是我有 7 个保持汇率的常数。我对此感到相当自豪,因为对于每种可能的组合,7 个费率比 12 个单独的费率要短得多。代码如下。
// Conversion Rates - START (as of October 14, 2018 @ 1:03 AM)
// Rates obtained from exchange-rates.org
private final double USD_TO_USD = 1;
//Convert to United States Dollars
private final double CAD_TO_USD = 0.76792;
private final double EUR_TO_USD = 1.1407;
private final double YEN_TO_USD = 0.008923;
//Convert from United States Dollars
private final double USD_TO_CAD = 1.3022;
private final double USD_TO_EUR = 0.87662;
private final double USD_TO_YEN = 112.06;
// Conversion Rates - END
我的方法背后的思考过程是将所有内容转换为美元,然后从美元转换为目标货币。我不确定如何进一步浓缩这一点,所以这是我遇到的问题之一。
我遇到的主要问题是精度。由于该课程主要基于商业数学,因此这些程序通常用于转换数百万/数十亿的货币。我知道 double 已经有自己的精度继承问题,但我不确定要使用哪些其他数据类型。我遇到过 BigDecimal,我会在发布后研究一下。
据我了解,汇率的小数位数会直接影响结果的精度。汇率右侧的数字越多;更好。我是否应该养成包含大量小数点的习惯,以使出现精度问题变得非常困难?或者使用 BigDecimal 通常会解决问题吗?
我考虑过放弃使用 double 并改用 int;所以不是双重持有 5.00,而是持有 500 的整数;但在这一点上,我不确定“正确”的继续方式。
所以我来问你们好人:D
我很乐意尽可能多地学习,因此我们非常感谢您提供任何帮助。
谢谢
更新: 我花了一些时间检查了 BigDecimal,我得到了它的工作;除了我现在偏离的数量从 1 到 10 不等(在非常大的数字中可能更多,但我没有用不同的数字测试超过 5 次)。
在我的测试中,我将 98765432.00 日元兑换成美元,汇率为 1 日元 = 0.008907 美元。根据我当时用来验证的网站 - 以美元计算的结果应该是 879,701.24 美元;但我的程序获得了 879,703.70 美元。甚至我的科学计算器也得到了和我的 java 程序一样的东西。
【问题讨论】:
要么使用BigDecimal
,要么将所有内容转换为long
。 int
可能不足以保存乘法结果
BigDecimal。绝对是 BigDecimal。永远不要使用浮点数来表示货币。
您不需要有最后 3 次的转化率。 4费就够了。如果说您想从 CAD 转换为 EUR 只需 CAD$ * (CAD_TO_USD / EUR_TO_USD);
也不需要标识常量。你只需要 3 个常量。
@RaymondTey,我从来不知道你能做到这一点。将欧元转换为日元是否也遵循 YEN = EUR * (EUR_TO_USD/YEN_TO_USD)?
【参考方案1】:
只需继续使用 BigDecimal 和 BigDecimal 一样实现您的方法,您不会丢失任何精度,但使用 double 时,您在处理更大的数字时可能会丢失。
请通过以下 *** 链接了解有关 BigDecimal 的更多信息: Double vs. BigDecimal?
你在正确的轨道上,继续摇摆和快乐学习。
【讨论】:
嗨,我花了一些时间检查了 BigDecimal,我得到了它的工作;除了我现在偏离的数量从 1 到 10 不等(在非常大的数字中可能更多,但我没有用不同的数字测试超过 5 次)。在我的测试中,我将 98765432.00 日元兑换成美元,汇率为 1 日元 = 0.008907 美元。根据我当时用来验证的网站 - 以美元计算的结果应该是 879,701.24 美元;但我的程序获得了 879,703.70 美元。甚至我的科学计算器也得到了和我的 java 程序一样的东西。【参考方案2】:这是另一个实现:
给定这样的货币汇率列表:
USD/GBP => 0.75
GBP/AUD => 1.7
AUD/JPY => 90
GBP/JPY => 150
JPY/INR => 0.6
Write a method
double convert(String sourceCurrency, double amount, String destCurrency);
==============
package test;
import java.util.*;
public class CurrencyConvertor
private Map<String, Map<String, Double>> mapping = new HashMap<String, Map<String, Double>>();
private boolean bInit = false;
private boolean bFound = false;
double convert(String src, double amount, String dst) throws Exception
if (src.equals(dst))
return amount;
if (!bInit)
init();
bInit = true;
bFound = false;
if (mapping.get(src) == null)
throw new Exception("Invalid conversion");
List<String> visited = new ArrayList<String>();
visited.add(src);
double d1 = getRate(visited, src, dst, 1);
if (bFound)
return d1 * amount;
throw new Exception("No mapping invalid conversion");
private double getRate(List<String> visited, String src, String dst, double rate) throws Exception
if (bFound == true)
return rate;
if (mapping.get(src).get(dst) != null)
bFound = true;
return rate * mapping.get(src).get(dst);
double origRate = rate;
for (String sInt : mapping.get(src).keySet())
if (visited.contains(sInt))
continue;
visited.add(sInt);
rate = getRate(visited, sInt, dst, rate * mapping.get(src).get(sInt));
if (bFound == true)
return rate;
visited.remove(sInt);
rate = origRate;
return origRate;
private void init()
// Invalid case data, EUR to INR
insert("EUR", "USD", 1.2);
insert("USD", "EUR", 0.75);
insert("YEN", "INR", 1.2);
insert("INR", "YEN", 0.75);
// Valid case data, EUR to INR
// insert("EUR", "USD", 1.2);
// insert("USD", "GBP", 0.75);
// insert("GBP", "AUD", 1.7);
// insert("AUD", "JPY", 90);
// insert("GBP", "JPY", 150);
// insert("JPY", "INR", 0.6);
//
// insert("USD", "EUR", 1.0/1.2);
// insert("GBP", "USD", 1.0/0.75);
// insert("AUD", "GBP", 1.0/1.7);
// insert("JPY", "AUD", 1.0/90);
// insert("JPY", "GBP", 1.0/150);
// insert("INR", "JPY", 1.0/0.6);
private void insert(String src, String dst, double rate)
if (mapping.get(src) == null)
Map<String, Double> map = new HashMap<String, Double>();
map.put(dst, rate);
mapping.put(src, map);
else if (mapping.get(src).get(dst) == null)
mapping.get(src).put(dst, rate);
public static void main(String args[])
try
double d = new CurrencyConvertor().convert("EUR", 100, "INR");
catch (Exception e)
// TODO Auto-generated catch block
e.printStackTrace();
【讨论】:
以上是关于Java中的货币转换器具有精度和浓缩问题的主要内容,如果未能解决你的问题,请参考以下文章
如何将具有 Decimal 的 spark DataFrame 转换为具有相同精度的 BigDecimal 的 Dataset?