简体   繁体   English

Java 中的货币转换器具有精度和压缩问题

[英]Currency Converter in Java having precision and condensing issues

I have gotten an assignment that is to be written in Java.我收到了一份要用 Java 编写的作业。

We are to develop a currency conversion application which asks the currency they are converting from, the amount of said currency, and the currency they wish to convert to.我们将开发一个货币兑换应用程序,询问他们兑换的货币、所述货币的数量以及他们希望兑换的货币。

The instruction noted we should include 4 currencies to convert from/to.该说明指出我们应该包括 4 种货币来转换。

I got the assignment done early and I went to show my professor and she noted a couple of issues with it.我很早就完成了作业,我去给我的教授看,她注意到了一些问题。 She likes the organisation and the clarity of the code, but she thinks I can make it a bit smaller and fix an issue I have with decimal precision.她喜欢代码的组织和清晰度,但她认为我可以让它更小一点,并解决我在十进制精度方面遇到的问题。

In regards to the making of it shorter, her main argument was that I have 7 constants which hold the exchange rates.关于让它更短,她的主要论点是我有 7 个常量来保持汇率。 I was rather proud of that since 7 rates is alot shorter than 12 individual rates for every possible combination.我为此感到相当自豪,因为对于每种可能的组合,7 个费率比 12 个单独费率要短得多。 Code is below.代码如下。

// 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

My thought process behind my methodology is to convert everything to US Dollars, then convert from US Dollars to the destination currency.我的方法背后的思考过程是将所有东西都转换为美元,然后从美元转换为目标货币。 I am unsure of how to condense this any further, so that is the one of the issues I am having.我不确定如何进一步浓缩,所以这是我遇到的问题之一。

The main issue I am coming across is precision.我遇到的主要问题是精度。 Since the class is largely based on business mathematics, the programs are generally used to convert millions/billions of currency.由于该课程主要基于商业数学,因此这些程序通常用于转换数百万/十亿的货币。 I know that double already has its own inherit issues with precision, but I am unsure of what other data types to use.我知道 double 已经有它自己的精度继承问题,但我不确定要使用哪些其他数据类型。 I have come across BigDecimal, and I will take a look into that after posting this.我遇到了 BigDecimal,我会在发布这个后研究一下。

To my understanding, the number of decimal points in the exchange rate will directly affect the precision of the result.据我了解,汇率中的小数位数会直接影响结果的精度。 the more numbers to the right of the rate;汇率右侧的数字越多; the better.更好。 Should I make a habit of including a very large amount of decimal points to make it very difficult to have the precision issue arise?我是否应该养成包含大量小数点的习惯,以便很难出现精度问题? Or would the use of BigDecimal usually solve the issue.或者使用 BigDecimal 通常会解决问题。

I have considered dropping the use of double and use int instead;我已经考虑放弃使用 double 并使用 int 代替; so instead of a double holding 5.00, I would have an integer holding 500;所以不是双重持有 5.00,我会有一个持有 500 的整数; but at this point, I am unsure of the "proper" way to proceed.但在这一点上,我不确定“正确”的继续方式。

So I came to ask you fine people :D所以我是来问你们好人的 :D

I am happy to learn as much as I can, so any assistance is appreciated.我很高兴尽可能多地学习,因此感谢任何帮助。

Thanks谢谢

UPDATE: I took some time to check out BigDecimal, and I got it working;更新:我花了一些时间来检查 BigDecimal,我让它工作了; except I am now off by an amount ranging from 1 to 10 (might be more in very very large numbers, but I didn't test it more than 5 times with different numbers).除了我现在减少了 1 到 10 的数量(在非常非常大的数字中可能更多,但我没有用不同的数字测试它超过 5 次)。

In my testing, I converted 98765432.00 Japanese Yen to US Dollars, with a rate of 1 YEN = 0.008907 US Dollars.在我的测试中,我将 98765432.00 日元转换为美元,汇率为 1 日元 = 0.008907 美元。 According to the website I used to verify at the time - the result in US Dollars should be USD$879,701.24;根据我当时用来验证的网站——以美元计算的结果应该是USD$879,701.24; but I am getting $879,703.70 on my program.但我的程序获得了 879,703.70 美元。 Even my scientific calculator is getting the same thing that my java program is getting.甚至我的科学计算器也得到了与我的 java 程序得到的相同的结果。

Just go ahead with your approach of implementing with BigDecimal as with BigDecimal you won't lose any precision but with double there is a chance of losing when you are dealing with larger numbers.继续使用 BigDecimal 的方法,就像使用 BigDecimal 一样,您不会失去任何精度,但是使用 double 时,在处理更大的数字时有可能会丢失。

Please go through the below stackoverflow link to get more idea on BigDecimal: Double vs. BigDecimal?请通过下面的 stackoverflow 链接获得更多关于 BigDecimal 的想法: Double vs. BigDecimal?

You are on the right track, keep rocking and happy learning.你走在正确的轨道上,不断摇摆,快乐学习。

Here is another implementation:这是另一个实现:

Given a list of currency exchange rates like this:给定一个像这样的货币汇率列表:

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();
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM