Ответ 1
Вы запутались, потому что 49 - значение ASCII целого числа 1. Таким образом, вы можете разделить символ на целое число, после чего вы можете увидеть целочисленное значение.
Integer.parseInt(String.valueOf(mi).charAt(1)):
Я пытаюсь извлечь вторую цифру из длинной переменной.
long mi = 110000000;
int firstDigit = 0;
String numStr = Long.toString(mi);
for (int i = 0; i < numStr.length(); i++) {
System.out.println("" + i + " " + numStr.charAt(i));
firstDigit = numStr.charAt(1);
}
Когда я печатаю firstDigit = numStr.charAt(1)
на консоли. Я получаю 1
, который ожидается, но когда цикл заканчивается, firstDigit
имеет 49
.
Немного смущает почему.
Вы запутались, потому что 49 - значение ASCII целого числа 1. Таким образом, вы можете разделить символ на целое число, после чего вы можете увидеть целочисленное значение.
Integer.parseInt(String.valueOf(mi).charAt(1)):
Поскольку 49 - это значение ASCII char '1'.
Поэтому вы не должны напрямую назначать char int.
И вам здесь не нужен цикл, который в любом случае сохраняет ovveriding текущее значение с charAt(1)
.
int number = numStr.charAt(1) - '0'; // substracting ASCII start value
Вышеприведенное утверждение внутренне работает как 49 -48 и дает вам 1.
Если вы чувствуете, что это смущает, как утверждают другие, используйте Character.getNumericValue();
Или, хотя мне не нравится ""+
hack, ниже должно работать
int secondDigit = Integer.parseInt("" + String.valueOf(mi).charAt(1));
Вероятно, вы ищете Character.getNumericValue(...)
i.e.
firstDigit = Character.getNumericValue(numStr.charAt(1));
В противном случае, поскольку переменная firstDigit
имеет тип int
, это означает, что вы назначаете ASCII-представление символа '1', который равен 49, а не целому числу по указанному индексу.
Также обратите внимание, что, поскольку вас интересует только конкретная цифра, нет необходимости вставлять оператор firstDigit = numStr.charAt(1);
внутри цикла.
а просто сделайте следующее вне цикла.
int number = Character.getNumericValue(numStr.charAt(1));
вам нужно только определить firstDigit как переменную типа char, поэтому напечатать в качестве символа. поскольку вы определяете как переменную int, это значение является значением ASCII char '1': 49. Вот почему вы получаете 49 вместо 1.
ответ Integer.parseInt(String.valueOf(mi).charAt(1)+"");
правильный.
Однако , если мы хотим рассмотреть performace в нашей программе, нам нужны некоторые улучшения.
Нам нужно много времени, Integer.parseInt()
и String.valueOf()
. И всегда пользовательские методы намного быстрее, чем Integer.parseInt()
и String.valueOf()
. см. простые тесты.
Таким образом, решение с высокой производительностью может выглядеть следующим образом:
int y=0;
while (mi>10)
{
y=(int) (mi%10);
mi=mi/10;
}
System.out.println("Answer is: " + y);
чтобы проверить его:
long mi=4642345432634278834L;
int y=0;
long start = System.nanoTime();
//first solution
//y=Integer.parseInt(String.valueOf(mi).charAt(1)+"");
//seconf solution
while (mi>10)
{
y=(int) (mi%10);
mi=mi/10;
}
long finish = System.nanoTime();
long d = finish - start;
System.out.println("Answer is: " + y + " , Used time: " + d);
//about 821 to 1232 for while in 10 runs
//about 61225 to 76687 for parseInt in 10 runs
Выполнение манипуляций с строками для работы с числами - это почти всегда неправильный подход.
Чтобы получить вторую цифру, используйте следующее:
int digitnum = 2;
int length = (int)Math.log10(mi));
int digit = (int)((mi/Math.pow(base,length-digitnum+1))%base);
Если вам нужна другая цифра, чем цифра второго изменения.
Чтобы избежать неопределенности в отношении чисел с плавающей запятой, вы можете использовать целочисленную математическую библиотеку, такую как guavas IntMath
Давайте посмотрим
System.out.println(numStr.charAt(1));
firstDigit = numStr.charAt(1);
System.out.println(firstDigit);
Результат не будет таким же, как вы получите
1
49
Это происходит потому, что ваш firstDigit - int. Измените его на char, и вы получите ожидаемый результат
Вы также можете сделать, как показано ниже,
firstDigit = Integer.parseInt( numStr.charAt(1)+"");
Таким образом, он будет печатать вторую цифру из длинного числа.
Некоторые вещи, которые еще не были упомянуты:
Вторая цифра для целых типов данных undefined, если длинное число равно 0-9 (Нет, это не ноль. Целые числа не имеют десятичных знаков, это верно для чисел с плавающей запятой. Даже тогда вы должны вернуть undefined для NaN или значение бесконечности). В этом случае вы должны вернуть часового, например, например. -1, чтобы указать, что нет второй цифры.
Использование log10 для получения определенных цифр выглядит элегантно, но они являются 1. одной из наиболее дорогостоящих функций и 2. часто дают неверные результаты в случаях краев. Я дам несколько контрпримеров позже.
Производительность может быть улучшена далее:
public static int getSecondDigit(long value) {
long tmp = value >= 0 ? value : -value;
if (tmp < 10) {
return -1;
}
long bigNumber = 1000000000000000000L;
boolean isBig = value >= bigNumber;
long decrement = isBig ? 100000000000000000L : 1;
long firstDigit = isBig ? bigNumber : 10;
int result = 0;
if (!isBig) {
long test = 100;
while (true) {
if (test > value) {
break;
}
decrement = firstDigit;
firstDigit = test;
test *= 10;
}
}
// Remove first
while (tmp >= firstDigit) {
tmp -= firstDigit;
}
// Count second
while (tmp >= decrement) {
tmp -= decrement;
result++;
}
return result;
}
Сравнение: 1 000 000 случайных длин.
String.valueOf()/Character.getNumericValue(): 106 мс
Log/Pow by Taemyr: 151 мс
Div10 от @Голамали-Иран: 45 мс
Рутина выше: 30 мс
Это еще не конец, это может быть еще быстрее при помощи таблиц поиска уменьшая 1/2/4/8, 10/20/40/80 и избегая использования умножения.
попробуйте это, чтобы получить второй char из ваших длинных
mi.toString().charAt(1);
Как получить код ASCII
int ascii = 'A';
int ascii = 'a';
Итак, если вы назначаете символ целому числу, целое число будет содержать значение ASCII
этого символа. Здесь я явно дал значения, в вашем коде вы вызываете метод, который возвращает символ, поэтому вы получаете ASCII
вместо цифры.