Конвертер валют в java, имеющий проблемы с точностью и сжатием

Я получил задание, которое должно быть написано на 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 может быть недостаточно, особенно для хранения результата умножения

Ivan 26.10.2018 04:04

BigDecimal. Определенно BigDecimal. Никогда не используйте что-либо с плавающей запятой для представления валюты.

Hovercraft Full Of Eels 26.10.2018 04:05

Вам не обязательно иметь последние 3 коэффициента конверсии. Достаточно 4 баллов. Если, скажем, вы хотите конвертировать из CAD в EUR, просто CAD $ * (CAD_TO_USD / EUR_TO_USD);

Raymond Tey 26.10.2018 04:06

Также нет необходимости в константе идентичности. Вам нужно всего 3 константы.

Hovercraft Full Of Eels 26.10.2018 04:10

@RaymondTey, я никогда не знал, что ты сможешь это сделать. Следует ли этому примеру, что для конвертации евро в иены будет YEN = EUR * (EUR_TO_USD / YEN_TO_USD)?

Bryan Douglas 26.10.2018 05:03

Да что правильно. И да, вам даже не требуется USD_TO_USD. И да, технически это не должно быть постоянным, поскольку эти изменения

Raymond Tey 26.10.2018 05:57

Отлично, я это сделаю. Я решил, что они должны быть константами, поскольку они вообще не меняются во время выполнения; они жестко запрограммированы.

Bryan Douglas 26.10.2018 06:15
1
7
1 039
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Просто продолжайте свой подход к реализации с BigDecimal, так как с BigDecimal вы не потеряете никакой точности, но с double есть шанс проиграть, когда вы имеете дело с большими числами.

Пожалуйста, перейдите по приведенной ниже ссылке stackoverflow, чтобы получить больше информации о BigDecimal: Double против BigDecimal?

Вы на правильном пути, продолжайте раскачиваться и с удовольствием учитесь.

Привет, я потратил некоторое время, чтобы проверить BigDecimal, и у меня все заработало; за исключением того, что сейчас я отключен на сумму от 1 до 10 (может быть больше в очень очень больших количествах, но я не тестировал это более 5 раз с разными числами). В ходе тестирования я конвертировал 98765432,00 японских иен в доллары США по курсу 1 иена = 0,008907 долларов США. Согласно веб-сайту, который я использовал для проверки в то время, результат в долларах США должен составить 879 701,24 доллара США; но по моей программе я получаю 879 703,70 долларов. Даже мой научный калькулятор получает то же самое, что и моя Java-программа.

Bryan Douglas 26.10.2018 07:00

Вот еще одна реализация:

Учитывая список курсов обмена валют, подобный этому:

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

Другие вопросы по теме