当前位置: 首页 > 知识库问答 >
问题:

Java中的货币转换器存在精度和压缩问题

汝才良
2023-03-14

我得到了一份用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;我会有一个双精度的整数,而不是一个双精度的整数;但在这一点上,我不确定“正确”的方式进行。

所以我来问你们这些好人:D

我很高兴能学到尽可能多的东西,所以任何帮助都很感激。

谢谢

更新:我花了一些时间检查BigDecimal,我让它工作了;但我现在的测试量从1到10不等(在非常大的数字中可能会更多,但我没有用不同的数字测试超过5次)。

在我的测试中,我将98765432.00日元兑换成美元,兑换率为1日元=0.008907美元。根据我当时用来核实的网站——以美元计算的结果应该是879701.24美元;但我的项目得到了879703.70美元。甚至我的科学计算器也得到了与java程序相同的结果。

共有2个答案

长孙永思
2023-03-14

下面是另一个实现:

给出如下货币汇率列表:

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();
        }
    }
}
陈斌蔚
2023-03-14

只要继续使用BigDecimal实现的方法,就像使用BigDecimal一样,你不会失去任何精度,但是使用两倍,当你处理较大的数字时,就有可能失去精度。

请通过下面的stackoverflow链接了解关于BigDecimal的更多信息:Double vs.BigDecimal?

你在正确的轨道上,继续摇摆,快乐地学习。

 类似资料:
  • 我读过不同的Q 脚本: Raddo公司在英国、法国和美国设有3个分支机构。拉德多有基础货币美元。预算是以美元编制的。Raddo商店支持数据库中的库伦奇汇率。 英国员工以英镑创建采购订单,法国员工以欧元创建采购订单。 问题1:采购订单/订单项目数据库表中应存储哪些内容-分行所在地货币和当前汇率或以基础货币美元表示的换算金额?请记住,汇率必须是创建采购订单时的汇率。 问题2:转换什么以及何时能够生成美

  • 问题内容: 我有一个文本框,其中将包含 货币 字符串,然后需要将该字符串转换为双精度以对其执行一些操作。 → 这需要在所有客户端发生。我别无选择,只能将 货币 字符串保留为输入的 货币 字符串,但需要将其强制转换/转换为双精度以进行一些数学运算。 问题答案: 删除所有非点/数字:

  • 我知道由于基数2计算而产生的双倍问题: 我明白BigDecimal应该用于货币相关的计算,但在我的情况下,小的精度损失是可以接受的,因为我需要做的所有货币计算都是将货币C1转换为货币C2,然后再转换回货币C1。唯一的问题是,当我用5个十进制精度向客户显示结果时,转换后的C1的两个值应该匹配。 现在我想弄清楚,在最坏的情况下,这个值可能会在这个转换上漂移多少?哪些数字可能导致最坏的情况?

  • 问题内容: 我正在应用程序中处理许多不同的货币,我想知道将它们存储在SQLite3数据库中的“最佳”方法是什么。 我倾向于定点表示(即,将它们存储为整数,其中$ 3.59被存储为359,¥400被存储为40000)。这是一个好主意吗?如果我的输入数据以后更改并且需要更高的精度怎么办? 问题答案: 鉴于SQLite 3将最多使用8个字节来存储INTEGER类型,除非您要使用大于10 ^ 16的数字,

  • 在我们继续之前,我们需要先来知道“菲亚特”或“菲亚特货币”的含义。 菲亚特货币由政府宣布为其控制的领土内的法定货币。仅因政府监管或法律而具有价值的菲亚特货币不受黄金或白银等实物商品的支持。法定货币的价值来自供需关系和发行政府的稳定性,而不是支持它的商品的价值。它基于经济的信念和信誉。大多数现代纸币都是法定货币。 每个加密货币的新手都想知道如何兑现比特币或从比特币中提取到法定货币(美元,欧元,印度卢

  • 我很难找到解决汇率问题的好办法。我花了一整天的时间来思考这个问题,并为所有情况提供了优雅而快速的解决方案。 声明: 我们有一些汇率,比如。。。 欧元兑美元- 这个利率不是真实的,可能每天变化一次。利率的数量可能和世界上的货币一样大(大约150种)。 我们被要求将一笔钱从任何一种货币兑换成另一种货币,我们应该根据汇率给出答案(如果可以的话)。 最好的情况是,如果你的汇率是直接的(出现在清单上),在最