Перевод из Десятичная система счисления в восьмеричную

Рейтинг: 0Ответов: 3Опубликовано: 18.07.2023

Изучаю Java совсем недавно и ни как не могу разобраться с алгоритмом преобразования десятичной системы в восьмеричную. Ни как не могу понять зачем нужен метод (Math.pow(10, i) для чего он здесь? Что он дает? Можно ли обойтись без него?

int decimal = 15450; 
int octal = 0;
for (int i = 0; 0 < decimal; i++){
    octal = (int)(octal + (decimal % 8)*(Math.pow(10, i)));
    decimal = decimal / 8;
}
System.out.println(octal);

Ответы

▲ 1Принят

В вашем коде происходят две вещи. Первая: из числа извлекаются цифры в восьмеричной системе счисления:

  • 15450 = 8 · 1931 + 2;
  • 1931 = 8 · 241 + 3;
  • 241 = 8 · 30 + 1;
  • 30 = 8 · 3 + 6;
  • 3 = 8 · 0 + 3.

Выделенные цифры образуют восьмеричное представления числа: 1545010 = 361328.

Вторая вещь: восьмеричные цифры умножаются на степени десятки: 3·104 + 6·103 + 1·102 + 3·101 + 2·100 = 3613210.

Полученное десятичное число выглядит на печати как восьмеричное. Получился нужный результат - программа напечатала восьмеричное представление десятичного числа.

Это плохой способ из-за переполнения. 100000000010 = 73465450008. Но 734654500010 > 214748364710 = 231 - 1 - максимальное значение int. Во время печати произойдёт переполнение, вы получите чепуху.

То что задействована вещественная арифметика тоже программу не красит.

Это рабочий, корявый, избыточный способ печатать небольшие целые числа в восьмеричном формате.

Рабочее решение (одно из) состоит в том чтобы накопить цифры в буфере, развернуть буфер задом-наперёд и напечатать. Никаких переполнений и загадочных вещественных вычислений:

int decimal = 15450;
StringBuilder sb = new StringBuilder();
for (int n = decimal; n > 0; n /= 8) {
    sb.append(n % 8);
}
if (sb.length() == 0) {
    sb.append(0);
}
System.out.println(sb.reverse());
▲ 1

Использование вещественной арифметики и приведения типа излишне.

Чтобы получить строку в нужной системе счисления, существуют стандартные методы Integer::toOctalString(int i), или же в любую целочисленную систему Integer::toString(int i, int radix) / Integer::toUnsignedString(int i, int radix)

Если задача реализовать своё преобразование, чтобы десятичное число выглядело как восьмеричное, можно использовать побитовые операции:

public static int toOct(int dec) {
    int sign = dec < 0 ? -1 : dec > 0 ? 1 : dec; // запомнить знак
    dec *= sign;
    int res = 0;
    int p = 1;
    while (dec > 0) {
        res += p * (dec & 07); // взять три последних бита 0b111
        dec >>= 3;             // сдвиг вправо вместо деления
        p *= 10;               // следующий "восьмеричный" разряд
    }
    return sign * res;
}

Тесты

System.out.println(toOct(15));   // 17
System.out.println(toOct(-15));  // -17
System.out.println(toOct(65));   // 101
System.out.println(toOct(3200)); // 6200
▲ 0

Это метод здесь нужен, чтобы получить очередную цифру "восьмеричного представления" числа путем умножения восьмеричной цифры (decimal % 8) на степень десятки. Почему десятки? - да потому что выбран такой способ упаковки восьмеричных цифр в целое число, что его строковое представление совпадает со строковым восьмеричным представлением исходного числа.

Нужен ли метод pow здесь на самом деле? С точки зрения оптимизации - нет, даже вреден, вещественная арифметика тут нафиг не нужна. С точки зрения написавшего - наверное, нужен, ему так кажется короче и понятнее.

Вот без него:

    int decimal = 15450; 
    int octal = 0;
    for (int p10 = 1; 0 < decimal; p10 *= 10){
        octal = octal + (decimal % 8) * p10;
        decimal = decimal / 8;
    }
    System.out.println(octal);