Как перевести двоичное число в десятичное java
Перейти к содержимому

Как перевести двоичное число в десятичное java

  • автор:

Перевода из двоичной системы счисления в десятичную и обратно с нуля

Из двоичной в десятичную: просто умножаете число на степени двойки. Например, 1110 = 1*2^3+1*2^2+1*2^1+0*2^0=14. Из десятичной в другие. Делишь число на основание системы исчисления. Остаток записываешь в строку. Пока число > 0. Потом строку переворачиваешь(reverse).

21 ноя 2016 в 19:19
@user31238 Спасибо огромное. Получилось написать методы
– user219793
21 ноя 2016 в 20:22

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

Задание для метода toBinar (код ниже) поставлено не совсем корректно. Дело в том, что отрицательные значения хранятся иначе чем положительные. Они инвертированы и хранят в старшем бите знак. Например число -10 будет выглядеть как «11111111111111111111111111110110». Разумеется в int такое запихнуть не получится. Следовательно метод нельзя использовать для отрицательных чисел. Но даже для положительных чисел метод будет очень ограничен. Максимальное число которое можно поместить в int — это 2147483647 . 10 знаков. Значит максимальное число которое будет представлено единицами и нулями хранимыми в int — это 1111111111 = 1023 в десятичном формате. Но если изменить условие чтобы метод возвращал String, то достаточно убрать последний парсинг и возвращать строку как есть, тогда можно будет передавать и отрицательные числа и положительные любой длины. Также стоит обратить внимание на определение значения младшего бита. В подобных задачах часто встречается деление. Но во-первых — деление это дорогостоящая операция, а во-вторых этот метод дает не верные результаты для отрицательных чисел. Поэтому здесь используется побитовый сдвиг и добавление результата побитового «И».

public static int toBinar(int base10) < if (base10==0) return 0; StringBuilder result = new StringBuilder(); while (base10 != 0) < result.append(base10 & 1); base10 >>>= 1; > return Integer.parseInt(result.reverse().toString()); > 

В методе toDecimal комментарии излишни, он достаточно прост. Перебираются символы справа налево на каждом шаге к результату прибавляя текущее значение разряда в десятичном представлении, если символ это ‘1’

 public static int toDecimal(String base2) < char[] chars = base2.toCharArray(); int result = 0; int mult = 1; for (int i = base2.length()-1; i >= 0; i--) < if (chars[i]=='1') < result += mult; >mult*=2; > return result; > 

Как перевести двоичное число в десятичное java

символы майя

Для усвоения этого урока достаточно знать циклы for (while, do-while), оператор выбора switch, условный оператор **if **, знание и уверенное пользование арифметическим оператором modulo.

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

Мы уже рассматривали во главе, которая знакомила нас с while как из десятичных чисел получить двоичные.

Повторение, 78 превращаем в 1001110.

78 : 2 = 39 остаток: 0 39 : 2 = 19 остаток: 1 19 : 2 = 9 остаток: 1 9 : 2 = 4 остаток: 1 4 : 2 = 2 остаток: 0 2 : 2 = 1 остаток: 0 1 : 2 = 0 остаток: 1 

Давайте переведём двоичное число в десятичное. Давайте возьмём уже известное нам число 1001110. В одном байте восемь битов. Число 1001110 состоит из семи цифр. В таких случая часто дописывают недостающие ноли и 100_1110 превращается в 0100_1110. Это удобно и очень важно при визуализации чисел.

Порядковый номер цифры в числе 7 6 5 4 3 2 1 0
Степени двойки 2^7 2^6 2^5 2^4 2^3 2^2 2^1 2^0
Чему в итоге равны степени 128 64 32 16 8 4 2 1
Пример двоичного числа 0 1 0 0 1 1 1 0
Как считается десятичное 0*128 1*64 0*32 0*16 1*8 1*4 1*2 0*1
Результат вычислений 0 64 0 0 8 4 2 0

Сумма чисел из последней строчки 64+8+4+2 = 78

Если с приведёнными примерами всё понятно, то можно перейти дальше и записать оба примера в Java.

Переведём число из десятичной системы в двоичную, пока не забыли.

public static String convertDecimalToBinary(int decimal) < int remainder; String output = ""; while (decimal >0) < remainder = (decimal % 2); output = Integer.toString(remainder) + output; decimal = decimal / 2; >return output; > 

И обратно из двоичной в десятичную

public static int convertBinaryToDecimal(int binaryDigit) < int decimal = 0; int n = 0; int temp = 0; while (binaryDigit >0) < temp = binaryDigit % 10; decimal += temp * Math.pow(2, n); binaryDigit = binaryDigit / 10; n++; >return decimal; > 

Замечу, что это простейший метод преобразования, который работает только с целыми числами больше нуля. Однако краткость этого метода должна помочь понять суть методики. Единственное, что стоит особенно подчеркнуть — результат работы метода строковое значение.

Если поработать над читаемостью метода convertDecimalToBinary, то мы заметим, что у нас (как минимум) дважды используется magicNumber 2 . Если мы догадаемся назвать это число systemIndex, то это будет частью решения метода convertDecimalToAnything.

public static String convertDecimalToAnything(int decimalDigit, int systemIndex) < int remainder; String output = ""; while (decimalDigit >0) < remainder = (decimalDigit % systemIndex); output = Integer.toString(remainder) + output; decimalDigit = decimalDigit / systemIndex; >return output; > 

Теоретически, можно подумать как из бинарной системы перевести числа в любую другую систему. Но зачем? Если есть метод преобразования бинарного числа в десятичную систему, а потом в любую другую.

У нас только одна проблема, наша система работает с числами систем меньше десятичной. Для того, что бы нам одолеть системы свыше десятичной, нам надо понять, что происходит с числом, когда его делят на 11, 12, 13, 14, 15, 16 и так далее. И здесь нам должен помочь switch, который будет перехватывать результаты деления свыше 10 и подставлять в output вместо числовых значений буквенные A, B, C, D, E, F и так далее.

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

Дополнительные ссылки #

  1. Бинарные(двоичные) числа в Java — официальная документация.
  2. Троичный компьютер
  3. Шестнадцатеричная система
  4. Двадцатиричная система
  5. Шести десятеричная
  6. Двенадцатеричная система счисления
  7. Цифры майя
  8. Пример применения — https://smallseotools.com/de/rgb-to-hex/

Домашнее задание #

  1. Ознакомиться со всеми дополнительными ссылками.
  2. Написать метод, который “вычитывает из строковых литералов десятичные и двоичные числа. Используйте метод — » Integer.parseInt();
  3. Написать свой собственный класс ConvertDigits
    • добавить интерактивность, общение программы с пользователем.
    • не использовать цикл while.

Задачи с очень повышенным уровнем сложности. #

  1. Написать метод, который решает вопрос с делением на числа из систем свыше десятичной — 11-16.
  2. (Факультатив)Написать метод перевода числа из “любой” системы в десятичную. // Мы вернёмся к этому методу в будущем.

sadedv / IntegerToBinary.java

Save sadedv/ee4b5835c0ae609f68e0 to your computer and use it in GitHub Desktop.

Перевести число в различные системы счисления — Java (в шестнадцатиричную, бинарную (двоичную)) Integer to Binary, to Hex and to Octal

This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters

public class Main
public static void main ( String [] args )
Integer number = 255 ;
// Бинарный формат числа
String convert = Integer . toBinaryString ( number );
System . out . println ( convert );
// Восьмиричная форма
convert = Integer . toOctalString ( number );
System . out . println ( convert );
// Шеснадцатиричная форма
convert = Integer . toHexString ( number ). toUpperCase ();
System . out . println ( convert );
>
>

Преобразуем строки в числа в разных системах счисления

Одной из частых рутин на работе является преобразование и извлечение чисел из строк текста. Самый наивный и простой подход в языке Java при преобразовании строки в число, это использовать Double.parseDouble(String num) . Проблема этого метода в том, что он имеет баги в различных SDK, например в Android. Кроме того, данному методу не передаётся информация об основании системы счисления. Можно, конечно, использовать классы оболочки, передавая им в конструктор основание системы, но хотелось бы извлекать данную информацию из самой строки автоматически.

Исходная задача

Дана произвольная строка. Выяснить, составляет ли она какое-либо (действительное) число в определённых системах счисления. Вычислить знак числа. Выделить в строке мантиссу и экспоненту, обработать их отдельно, и перемножить друг на друга. Для простоты рассмотрим четыре системы счисления: десятичную, двоичную, восьмеричную и шестнадцатиричную.

Для каждой системы счисления, кроме десятичной определим соответствующий префикс:

У числа может быть задана экспонента. Определим три вида экспоненты, имеющие следующие префиксы:

  • ‘H’ | ‘h’ : десятичная экспонента для 16-ричных чисел, поскольку буква E уже занята (является цифрой 14 в данной системе).
  • ‘E’ | ‘e’ : десятичная экспонента для остальных чисел, чьё основание системы ниже 14.
  • ‘P’ | ‘p’ : двоичная экспонента для всех представленных чисел.

Пишем код

Так напишем же простой метод для преобразования строки в число из соответствующей системы счисления (указанной в строке) в десятичную. Данный метод должен корректно отделять целую часть от той, что следует после запятой (точки). Обработка знака и экспоненты будет дана ниже.

public class ProcessNumber < private static final String digits = "0123456789ABCDEF"; /* Преобразует строку num в десятичное число типа double из указанного основания base Может вызвать переполнение (выход за пределы диапазона целых чисел)! */ private static double parseNumber(String num, int base)< num = num.toUpperCase(); // digits are in UPPER_CASE double val = 0; int i = 0; while(i < num.length()) // пока не кончилась строка < char c = num.charAt(i); if(c == '.') < // нашли точку '.' i++; // Переместить на следующий символ и выйти из цикла. break; >int d = digits.indexOf(c); // Индексы совпадают с числами из [0..15] if(d == -1 || d >= base) return Double.NaN; val = base * val + d; i++; > int power = 1; // вычислить лишний порядок. while(i < num.length()) < char c = num.charAt(i); int d = digits.indexOf(c); if(d == -1 || d >= base) return Double.NaN; power *= base; // увеличиваем степень порядка на единицу val = base * val + d; i++; > return val / power; > >

Сейчас метод parseNumber() выполняет ровно одну задачу. Он пытается преобразовать строку num в число типа double, начиная с указанного основания base. Если обнаружен недопустимый символ в строке num, то метод вернёт специальную константу класса Double не-число (NaN — Not a Number).

Самому методу нужно передавать строку без экспоненты, знака, и префикса основания системы счисления. Их предстоит вычислить заранее. Если есть знак минус ( ‘-‘ ) то число просто умножается на минус единицу ( -1 ). Если есть экспонента, то число дополнительно умножается на неё. Прежде чем приступить к их вычислению, допустим, что нам уже известны данные компоненты. Напишем метод, который делает выбор на основе полученной информации, и выполняет соответствующее умножение преобразованного числа из заданного основания на полученную экспоненту и минус единицу, если необходимо.

public class ProcessNumber < // . parseNumber(String str, int base) < . >/* num - Число e - экспонента et - тип экспоненты base - основание системы счисления sign - знак числа (num > 0 => positive, num < 0 =>negative). esign - знак экспоненты. */ public static double parse(String num, String e, char et, int base, int sign, int esign) < if(num == null || num.length() == 0 || base < 1) // null значения =>NaN. return Double.NaN; double exp = 1; // Экспонента // Двоичная экспонента (по основанию 2) if((et == 'P' || et == 'p') && e != null && e.length() > 0) exp = Math.pow(2.0, parseNumber(e, 10)); // Десятичная экспонента (по основанию 10) else if( (et == 'E' || et == 'e' || et == 'H' || et == 'h') && e != null && e.length() > 0) exp = Math.pow(10.0, parseNumber(e, 10)); //e == null or e.length() == 0. // Указан тип экспоненты, но сама она отсутствует else if(et == 'E' || et == 'e' || et == 'H' || et == 'h' || et == 'P' || et == 'p') < return Double.NaN; >else // et is not [PpEeHh] => ignore exponent (exp == 1) (Нет экспоненты) exp = 1; if(esign < 0) exp = 1 / exp; double result = parseNumber(num, base); // Преобразовать численную часть. result = (result == Double.NaN) ? result : result * exp; if(sign < 0) result = 0 - result; //make number negative (include minus sign) return result; >>

Методу parse() уже передаются вычисленные компоненты числа, а именно: само число num, его экспонента e, основание экспоненты et, основание системы самого числа base и знак числа sign. В данном методе уже предусмотрена защита от противоречивых данных (например, когда экспонента равна null, но указан её тип, или когда основание системы счисления не является натуральным числом (меньше единицы)). В простом случае, если строка равна null, то данный метод вернёт не-число (NaN). Метод выполняет простую задачу, он просто вычисляет множители итогового выражения result, и выполняет умножение преобразованных строк (экспоненты и самого числа без неё) на переменную знака sign. А вызываемый метод processNumber() переводит строку компонента в число.

Теперь остаётся написать последний метод, который вычисляет знак, экспоненту и основание системы. Ниже дан его код.

public class ProcessNumber < . // parseNumber(String num, int base) < . >// parse(String num, String exp, char etype, int base, int sign) < . >/* В отличие от parseNumber(String num, int base) автоматически вычисляет основание base, экспоненту e, и её тип, а также знак числа sign. В случае успешного вычисления, передаёт вычисленные элементы методу parse(), который делает выбор (условный переход) множителей и преобразование строковых компонент уже через parseNumber(num, base). */ public static double parseNumber(String str) < if(str == null || str.length() == 0) //null is NaN. return Double.NaN; int sign = 1; // знак числа. int esign = 1; // знак экспоненты. int base = 10; // по умолчанию основание равно 10. int i = 0; if(str.charAt(0) == '-') < // Минус ->sign < 0. sign = -1; i = 1; // перейти к следующему знаку. >if(i > 0 && i == str.length()) //str is '-' (строка состоит только из '-') return Double.NaN; // suffix '0x' => 16 (hex) if(str.charAt(i) == '0' && (i + 1 != str.length()) && str.charAt(i + 1) == 'x') < base = 16; i += 2; >//suffix '0b' => 2 (binary) else if(str.charAt(i) == '0' && (i + 1 != str.length()) && str.charAt(i + 1) == 'b') < base = 2; i += 2; >//suffix '0c' => 8 (octal) else if(str.charAt(i) == '0' && (i + 1 != str.length()) && str.charAt(i + 1) == 'c') < base = 8; i += 2; >if(i == str.length())// строки вида (-0x -0b -0c 0x 0b 0c) return Double.NaN; //Вычислить экспоненту. int idx = str.indexOf('H'); idx = (idx == -1) ? str.indexOf('h') : idx; idx = (idx == -1) ? str.indexOf('P') : idx; idx = (idx == -1) ? str.indexOf('p') : idx; idx = (idx == -1 && base != 16) ? str.indexOf('E') : idx; idx = (idx == -1 && base != 16) ? str.indexOf('e') : idx; char etype = (idx == -1) ? 'N' : str.charAt(idx); //Когда нет экспоненты (idx + 1) == 0. if(idx + 1 == str.length())// no more digits after exponent letter ('12E' or 'FFP') return Double.NaN; String exp = null; //Отрицательная экспонента, но нет цифр 'E-' or 'P-' or 'h-' if(str.charAt(idx + 1) == '-' && idx != -1 && idx + 2 == str.length()) return Double.NaN; //Отрицательная экспонента. 'E-2' or 'p-10' if(str.charAt(idx + 1) == '-' && idx != -1) < exp = str.substring(idx + 2); esign = -1; >else exp = str.substring(idx + 1); //Положительная экспонента (после idx следует цифра) idx = (idx == -1) ? str.length() : idx; //if no exponent then idx >

Данный метод начинает со стандартной проверки на null-значения. Далее, если строка не null и имеет символы, то проверяется её самый первый символ. Если он имеет знак минуса ( ‘-‘ ) то множитель sign становится равен (-1). Иначе он остаётся равен 1. После вычисления знака идёт вычисление основания системы счисления по префиксу строки. После обработки префикса, снова проверяется наличие оставшейся части символов в строке. Если больше символов нет, то опять возвращается не-число (NaN). Если префикс основания отсутствует, то основание base считается равным 10. Затем вычисляется экспонента exp числа и индекс idx её начала для её последующего отделения от исходной строки. После вычисления всех компонентов, управление передаётся методу parse().

Заключение

Метод достаточно хорош, но ещё не идеален. При выходе из диапазона значений стандартных типов, можно получить неверный результат (а именно, отрицательные числа, когда как строка представляет положительное число, и наоборот). Он минует исключение NumberFormatException, возвращая не-число NaN когда обнаруживает недопустимый символ (не принадлежащий диапазону цифр в основании) а также NullPointerException, так как есть проверки на null (сводящиеся к замене null на NaN).

Следует также отметить, что самая последняя процедура processNumber(String num) имеет место уже с готовой лексемой num, лишённой лишних пробельных символов. При дублировании знака числа (минуса), результат будет снова NaN. Также, если сама экспонента NaN то и итоговое значение будет NaN. Однако процедура допускает наличие лидирующих нулей вначале числа.

Данную утилиту можно использовать только уже с коллекцией строк (цепочек), заранее выделенных из входного потока.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *