Как мне разобрать нецелые восьмеричные числа в Java? - PullRequest
0 голосов
/ 14 февраля 2012

Это может быть невозможно, но я подумал, что спрашивать не повредит. У меня есть программа, которая должна преобразовать нецелые десятичные дроби в восьмеричную запись. Из того, что я могу сказать, Java может обрабатывать только целочисленные восьмеричные числа автоматически. Я собрал воедино что-то вроде клуджа, которое включает в себя разбиение числа на степени восьми, что-то вроде этого.

.abcd = x * (1/8) + y * (1/64) + z * (1/512) + ......

, который будет отображаться как "0.xyz", если это имеет смысл. Проблема в том, что это приводит к большому количеству ошибок округления / усечения длинных чисел. Есть ли лучший способ сделать это?

(редактировать) Вот алгоритм, который я использовал для обработки цифр справа от десятичной точки:

double floatPartNum = Double.parseDouble("0." + temps[1]);
     if (floatPartNum > 0) {
        int p = 1;
        result = result + ".";
        while (floatPartNum > 0 && p < 16) {
           double scale = 1/(Math.pow(8, p));
           int modT = (int)( floatPartNum / scale );
           result = result + modT;
           double modScale = (double)modT * scale;
           floatPartNum -= modScale;
           p++;
        }
     }

Ответы [ 4 ]

2 голосов
/ 14 февраля 2012

Я не знаю ни поддержки с плавающей запятой, ни фиксированной точки для восьмеричных чисел в базовой Java. Если вы покажете свой алгоритм извлечения восьмеричных цифр из десятичного числа, возможно, мы могли бы помочь уменьшить ошибку.

1 голос
/ 14 февраля 2012

Ваш p < 16 искусственно обрезает ваш вывод.Когда я пробую ваш код на 1.0/3.0, я получаю 0.252525252525252, но на самом деле в двойнике достаточно точности, чтобы добавить еще три восьмеричных цифры, что дает 0.252525252525252525, если вы измените его на p < 20.Но если вас беспокоят "длинные числа", то вы можете обнаружить, что double просто недостаточно для ваших нужд.

Кстати, ваш цикл можно значительно упростить, чтобы:

for(int p = 1; floatPartNum > 0 && p < 20; ++p)
{
    floatPartNum *= 8.0;
    result = result + (int)floatPartNum;
    floatPartNum -= (int)floatPartNum;
}

(проверено), что устраняет необходимость в Math.pow и так далее.(Math.pow работает, выполняя логарифмы и возведения в степень; это избыточное и потенциально склонное к округлению, когда вы просто умножаете на восемь.)

1 голос
/ 14 февраля 2012

В классах Float и Double есть несколько методов, которые позволяют вам получить побитовое представление числа; например Double.doubleToLongBits(double).

Затем можно извлечь части мантиссы и экспоненты из двойных битов и преобразовать их в восьмеричный формат без потери точности.


Однако, может быть проще просто исправить ваш текущий алгоритм. Я бы подумал, что вы должны реализовать ваш подход без потери точности. (Рассматривали ли вы возможность того, что точность уже была потеряна; т. Е. В процессах / вычислениях, которые в первую очередь вывели ваши числа?)

0 голосов
/ 14 февраля 2012

Как насчет чего-то еще подобного?(Мне жаль, что я не могу проверить этот код перед публикацией, я не рядом со своими инструментами программирования.)

...