Nano Hash - криптовалюты, майнинг, программирование

Получение второй цифры из длинной переменной

Я пытаюсь получить вторую цифру из длинной переменной.

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. Немного непонятно почему.

26.12.2017

  • Зачем вам цикл, если вам нужна только вторая цифра? 26.12.2017
  • Вторая цифра в какой системе исчисления? Шестнадцатеричный, десятичный, восьмеричный, двоичный, ...? 26.12.2017
  • Связанный: Что делает "0" в Java? 26.12.2017
  • Всякий раз, когда я задаю вопрос, который помечен как повторяющийся, меня минусуют слева, справа и по центру (и, конечно же, вниз). Тогда как этот получил девять голосов? 28.12.2017
  • Кажется, вы начинаете с переменной long? Зачем превращать это в строку? 31.12.2017
  • Ваш код возвращает 49, потому что это неправильно. Как только вы это исправите, будет возвращен правильный ответ, и, скорее всего, это будет 42. 30.03.2018

Ответы:


1

Вы запутались, потому что 49 - это значение ASCII целого числа 1. Таким образом, вы можете разобрать символ на целое число, тогда вы увидите целое значение.

    Integer.parseInt(String.valueOf(mi).charAt(1)):
26.12.2017
  • чтобы предотвратить The method parseInt(String) in the type Integer is not applicable for the arguments (char), вы должны использовать что-то вроде Integer.parseInt(String.valueOf(mi).charAt(1)+""); 26.12.2017

  • 2

    Потому что 49 - это значение ASCII для char '1'.

    Таким образом, вы не должны напрямую назначать char для int.

    И вам не нужен здесь цикл, который все равно продолжает проверять текущее значение с помощью charAt(1).

    int number = numStr.charAt(1) - '0'; // substracting ASCII start value 
    

    Приведенный выше оператор внутренне работает как 49 -48 и дает вам 1.

    Если вы чувствуете, что это сбивает с толку, как говорили другие, используйте Character.getNumericValue();

    Или, хотя мне не нравится ""+ хак, ниже должно работать

    int secondDigit = Integer.parseInt("" + String.valueOf(mi).charAt(1));
    
    26.12.2017

    3

    Вероятно, вы ищете Character.getNumericValue(...), т.е.

    firstDigit = Character.getNumericValue(numStr.charAt(1));
    

    В противном случае, поскольку переменная firstDigit имеет тип int, это означает, что вы назначаете ссылку представление ASCII символа '1', которое равно 49, а не целому числу по указанному индексу.

    Также обратите внимание, что, поскольку вас интересует только конкретная цифра, нет необходимости помещать оператор firstDigit = numStr.charAt(1); внутрь цикла.

    скорее, просто выполните следующее вне цикла.

    int number = Character.getNumericValue(numStr.charAt(1));
    
    26.12.2017

    4

    вам нужно только определить firstDigit как переменную типа char, поэтому она будет напечатана как символ. поскольку вы определяете переменную int, ее значение представляет собой значение ASCII для char '1': 49. вот почему вы получаете 49 вместо 1.

    26.12.2017

    5

    ответ Integer.parseInt(String.valueOf(mi).charAt(1)+""); правильный.

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

    У нас есть трудоемкие методы, 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
    
    26.12.2017
  • Если мы хотим учитывать производительность, мы определенно должны использовать (num / 10^{Log_10{num} - 1}) % 10 вместо этого цикла. Что намного, намного быстрее, чем другие альтернативы, но не совсем очевидно на первый взгляд для большинства людей, на которые я бы поставил. 26.12.2017
  • В java нет функции ^ (только для битовой операции), мы должны использовать метод Pow(), в этом случае мы должны использовать parseInt() и другие преобразования. Они так много времени в java. 26.12.2017
  • Это не должен быть настоящий код Java, больше LaTeX для написания математической формулы. 26.12.2017
  • @Voo Совершенно неправильно. Log10 и/или 10^ — элегантные, но численно чрезвычайно дорогие функции с плавающей запятой. Они также не являются точными на 100% из-за округления с плавающей запятой. 26.12.2017

  • 6

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

    Чтобы получить вторую цифру, используйте следующее;

    int digitnum = 2;
    
    int length = (int)Math.log10(mi));
    int digit = (int)((mi/Math.pow(base,length-digitnum+1))%base);
    

    Если вы хотите другую цифру, чем вторая цифра изменения.

    Чтобы избежать неопределенности в отношении чисел с плавающей запятой, вы можете использовать библиотеку целочисленных математических вычислений, например guavas IntMath

    26.12.2017
  • Хотя это математически правильный ответ, я признаю, что не смог доказать, что это дает правильный ответ при рассмотрении неточностей поплавка с ходу. 26.12.2017
  • @Voo Ответ обновлен, чтобы использовать только log10 со ссылкой на guava для чистой альтернативы int base. 26.12.2017

  • 7

    Давайте взглянем

    System.out.println(numStr.charAt(1));
    firstDigit =  numStr.charAt(1);
    System.out.println(firstDigit);
    

    Результат не будет таким же, как вы получите

    1
    49
    

    Это происходит потому, что ваш firstDigit равен int. Измените его на char, и вы получите ожидаемый результат.

    26.12.2017

    8

    Вы также можете сделать, как показано ниже,

    firstDigit = Integer.parseInt( numStr.charAt(1)+"");
    

    Таким образом, он напечатает вторую цифру из длинного числа.

    26.12.2017

    9

    Некоторые вещи, которые еще не были упомянуты:

    • Вторая цифра для целочисленных типов данных 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 от Тэмира: 151 мс
    Div10 от @Gholamali-Irani: 45 мс
    Подпрограмма выше: 30 мс

    Это не конец, это может быть еще быстрее, если таблицы поиска уменьшатся на 1/2/4/8, 10/20/40/80 и избегают использования умножения.

    26.12.2017
  • очень хорошее сравнение 26.12.2017

  • 10

    попробуйте это, чтобы получить второй символ вашего длинного

    mi.toString().charAt(1);
    
    26.12.2017

    11

    Как получить код ASCII

    int ascii = 'A';
    int ascii = 'a';
    

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

    26.12.2017
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..