Преобразование дроби из любой базы в десятичную — невозможно использовать отрицательные степени с большой десятичной

#java #bigdecimal

Вопрос:

Я нахожусь в процессе создания приложения для преобразования базы чисел.

Я застрял на том, как преобразовать дробную часть в десятичную перед преобразованием в целевую базу.

Например:

Пользователь выбирает from base 16 to base 20 .

Число в base 16 = ab.375

Расчет, который я пытаюсь закодировать для этого конкретного примера, таков:

 Base 16 to decimal calculation:

(ab.375)16 = (10 × 16 ^ 1)   (11 × 16 ^ 0)   (3 × 16 ^ -1)   (7 × 16 ^ -2)   (5 × 16 ^ -3) = (171.216064453125)10
 

У меня есть отдельный метод, который правильно выводит часть пользовательского ввода до десятичной точки. Моя проблема заключается в том, как учитывать дробную часть, и метод negative powers since BigDecimal pow не может быть < 0

Вот мой convertToDecimalFraction метод:

     public static String convertToDecimalFraction(int sourceBase, String fraction) {

        String[] fractionToConvertArray = ArrayUtilNoFraction.numberToArray(fraction);

        int basePowers = -1;

        BigDecimal integerToDecimalBig = BigDecimal.ZERO;

        for (String s : fractionToConvertArray) {
            integerToDecimalBig = integerToDecimalBig
                    .add(BigDecimal.valueOf(Integer.parseInt(s))
                            .multiply(BigDecimal.valueOf(sourceBase).pow(basePowers)));
            basePowers = basePowers - 1;
        }
        return integerToDecimalBig.toString();
    }
 

На случай, если вам интересно, вот мой ArrayUtilFraction.numberToArray :

     public static String[] numberToArray(String numberToConvert) {

        String[] numberToConvertArray = String.valueOf(numberToConvert).split("");

        String[] possibleValues = new String[]{
                "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
                "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
                "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
                "U", "V", "W", "X", "Y", "Z"
        };

        StringBuilder outputValues = new StringBuilder();
        int count = 0;

        for (String number : numberToConvertArray) {
            for (String value : possibleValues) {
                if (number.equalsIgnoreCase(value)) {
                    outputValues.append(count).append(" ");
                    break;
                } else {
                    count = count   1;
                }
            }
            count = 0;
        }
        return outputValues.toString().split(" ");
    }
 

Комментарии:

1. x^-n = 1/(x^n) надеюсь, это поможет

Ответ №1:

Вот несколько советов.

  • Нет необходимости постоянно использовать эту pow функцию. Рассмотрим базовое 16 значение 1EF.2DA .
  • Мощность будет 3 , так как у вас есть три цифры слева от radixPoint . Поскольку радиус будет 16 таким, установите свой начальный делитель равным
       divisor = BigDecimal.pow(16,3);
 
  • Затем удалите десятичную точку из строки, давая 1EF2DA .
  • Теперь, используя начальное значение b = BigDecimal.ZERO цикла, проведите цифры слева направо. charToBase10 является ли карта для перехода от исходного радиуса к base10 (например E to 14 )
        b = b.add(BigDecimal.valueOf(charToBase10.get(digit))
                    .multiply(divisor));
       divisor = divisor.divide(sourceRadix);
 
  • Каждый раз, проходя через цикл, b создается так, чтобы содержать это число. Так как делитель в конечном итоге будет меньше, чем 1 дробная часть, будет постепенно появляться.

И вот быстрый трюк для преобразования любого десятичного дробного значения в другое основание.

  • предположим, вы хотели преобразовать .45(10) в базовый 2 . Выходные данные будут добавлены в биты.
 2*.45 = 0.90 non-fraction portion is 0 so first bit is 0
2*.90 = 1.80 non-fraction portion is 1 so next bit is  1
2*.80 = 1.60 - next bit is 1
2*.60 = 1.20 - next bit is 1
2*.20 = 0.40 - next bit is 0
2*.40 = 0.80 - next bit is 0
2*.80 = 1.60 - next bit is 1  (and we have reached a repeating point)
So the answer is

bits = .0111001[10011001100110011....]
 

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

Комментарии:

1. Спасибо вам за это. Я относительно новичок в Java, поэтому с нетерпением жду возможности в ближайшее время поделиться своим завершенным приложением для обзора кода SO. Я предпочитаю кодировать свои собственные методы вместо использования встроенных методов, например charToBase10 , чтобы я мог узнать как можно больше. Пока речь идет не об оптимизации, а более или менее о понимании основ!

2. Всегда пожалуйста! Просто, чтобы вы знали, charToBase10 это не встроенный метод. Это экземпляр класса в API, который называется HashMap. В этом отношении он ничем не отличается от использования String или BigDecimal которые также являются классами в API.