Функция, которая возвращает цифру внутри числа

#c #c

#c #c

Вопрос:

Я хочу создать функцию, которая будет отображать число и позицию цифры, которые я хочу извлечь,

 int getDigit(int value, int positionFromLeft)
  

Скажем, getDigit(534, 2) вернет 3.

Какой может быть самый простой / эффективный способ написать эту функцию?

Комментарии:

1. ввод цифры за цифрой в вектор и индексация, когда требуется.

2. Я думаю, @Cameron имел в виду «покажите нам код»

3. Если вам удастся получить исходный файл на нескольких языках, пожалуйста, опубликуйте его. В любом случае, я предлагаю вам придерживаться одного языка для каждого файла: либо C , либо C 🙂

Ответ №1:

Во-первых, это будет намного проще, если вы готовы работать справа, а не слева (т. Е. от наименее значащей цифры).

Учитывая входные данные N, N выдаст наименьшую значащую цифру. X / 10 сдвинет X на одну цифру вправо, x / 100 сдвинет его на две цифры вправо и т.д.

Если вам действительно нужно начать слева, log10 должно получиться общее количество цифр.

Комментарии:

1. Ну, да — если вы измените вопрос, придумать ответ будет намного проще!

2. @Johathan: да, но я также ответил на заданный вопрос. Я бы отметил, что там, где он указывает, что цифры начинаются слева, перед ними стоит «Say», что обычно означает, что это возможный пример, не обязательно единственная возможность.

Ответ №2:

Все эти решения на основе строк пугают меня… Серьезно, ребята? :-/

 int getDigit(int value, int positionFromLeft)
{
    int posFromRight = 1;
    {
        int v = value;
        while (v /= 10)
              posFromRight;
    }
    posFromRight -= positionFromLeft - 1;
    while (--posFromRight)
        value /= 10;
    value %= 10;
    return value > 0 ? value : -value;
}
  

Обратите внимание, что передача значения, выходящего за рамки, для positionFromLeft не вернет никакого осмысленного значения как есть.

Комментарии:

1. Наконец, простое решение. Приветствия!

2. Ваш getDigit(1234567, 2) возвращает 5, а не 3. Так уж получилось, что при 534 3 является вторым слева и вторым справа.

3. Да, за исключением того, что ваше решение неверно. Неправильное значение, указанное слева, не равно правому! В вопросе указано positionFromLeft , то есть, если вы передаете 1, вам нужна самая значимая цифра, но вы возвращаете наименее значимую.

4. -1 решения на основе строк связаны с тем, что вы решили более легкую задачу, чем вопрос OP, и не ответили на вопрос OP.

5. В таком случае вы задали неправильный вопрос и зря потратили наше время… Потому что этот ответ определенно не решает вашу проблему, как было задано.

Ответ №3:

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

 int getDigit(int value, int positionFromLeft) {
    if (value < 0) positionFromLeft  ;

    std::stringstream ss;
    ss << value;

    std::string s = ss.str();
    if (positionFromLeft >= 1 amp;amp; positionFromLeft <= s.length())
        return s[positionFromLeft-1] - '0';
    else
        throw std::runtime_error("invalid digit position");
}
  

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

  • Что произойдет, если value значение отрицательное? Я решил игнорировать знак и считать с первой цифры.
  • Что, если позиция выходит за рамки? Я решил создать исключение.
  • Также существует вероятность value быть INT_MIN , поэтому простое взятие абсолютного значения не сработает.

Комментарии:

1. Я несколько раз пробовал это, но вместо этого использовал вектор. Это ss << значение, строка делает все намного чище. 🙂 спасибо!

2. Это не двуязычное решение, и вопрос помечен двуязычно.

3. @Jonathan: Ах, я пропустил тег C. Я добавил примечание о том, что это только C .

4. @Jonathan Leffler C и C не должны быть помечены в одном вопросе. Поэтому кого это волнует.

Ответ №4:

Другое рекурсивное решение этого старого вопроса (я изменил тип positionFromLeft на unsigned )

 int getDigit(int value, unsigned positionFromLeft) {
    assert(positionFromLeft > 0);
    if (positionFromLeft == 1) return abs(value) % 10;
    if (value == 0) return 0; // optimization: break out of recursion if 0 is reached
    return getDigit(value / 10, positionFromLeft - 1);
}
  

Смотрите ideone

Ответ №5:

Самый простой, но не обязательно лучший:

 int getDigit(int value, int positionFromLeft)
{
    char buf[sizeof(int)*3 2];
    if (sprintf(buf, "%d", value)-1U < positionFromLeft-1U) return -1;
    return buf[positionFromLeft-1U]-'0';
}
  

Примечание: Отредактировано, поскольку кто-то возражал (по-видимому) против того, чтобы snprintf не быть в C , и учитывать выходящую за границы позицию на основе одного. Теперь это немного менее просто…

Комментарии:

1. Но обратите внимание, что это недопустимо для C .

2. @aschepler: почему вы это утверждаете? Потому что она использует snprintf() то, чего нет в стандартном C ? Или по какой-то другой причине?

3. У вас возникают незначительные проблемы с управлением буфером, если positionFromLeft значение отрицательное или если число настолько короткое, что в нем нет N-й цифры. Также, для примера, вы возвращаете 4 вместо 3 (через единицу), но вы получаете правильный ответ, для getDigit(-534,2) которого у меня нет (пока).

4. Но sizeof(int)* 3 2 был аккуратным 🙂

5. Упс, неважно. Мой мозг почему-то думал, что в массиве, привязанном к buf , есть переменная.

Ответ №6:

 function getDigit(original,nonZeroIndexedIndex)
{
    return ((int)floor(original / pow(10, nonZeroIndexedIndex))) % 10;
}
  

по предложению @R..:

 function getDigit(original,nonZeroIndexedIndex)
{
    int tens [5] = { 1, 10, 100, 1000, 10000 };
    return ((int)floor(original / tens[nonZeroIndexedIndex - 1])) % 10;
}
  

Надеюсь, это поможет! Для меня это приятное небольшое обновление C 🙂

Комментарии:

1. о! упс! спасибо, что обратили на это внимание. Прошло много времени с тех пор, как я написал хоть строчку на C 🙂

2. pow ненадежна при использовании целых чисел. Просто используйте static const массив степеней 10. Их не так много.

3. Независимо от того, что это неправильный способ обхода, вам не нужен здесь ни пол, ни какая-либо плавающая точка. C , как и C, всегда использует целочисленные деления нижнего уровня.

4. Какой тип function ? И каковы типы аргументов функции? Это не C ; это может быть C89, если в области видимости есть typedef int function; , но в нем используются устаревшие функции C89.

Ответ №7:

Если вам действительно нужно считать слева, вы можете сделать это:

 uint8_t getDigitR(uint16_t value, uint8_t i) {
  uint32_t digit = 1;
  while (digit <= value)
    digit *= 10;
  while (i--) // if you start counting at 1
    digit /= 10;
  return (value / digit) % 10;
}
  

Но это, вероятно, на самом деле не более эффективно или проще, чем строковые решения, но поскольку это домашнее задание, возможно, есть несколько алгебраических вещей, которые нужно изучить, если не выполнять со строками 🙂

Однако вам нужно меньше места в стеке.

Ответ №8:

 int getDigit(int value, int positionFromLeft)
{
    char buffer[20];
    if (value > 0)
        value = -value;
    int len = snprintf(buffer, sizeof(buffer), "%d", value);
    int digit = 0;
    if (len > positionFromLeft amp;amp; positionFromLeft > 0)
        digit = buffer[positionFromLeft] - '0';
    return digit;
}
  

Это возвращает ноль, если вы запрашиваете цифру за пределами RHS числа. Трюк с отрицанием гарантирует, что значение всегда отрицательное (и никогда не возникает проблем с отрицанием INT_MIN ), а затем есть знак минус, поэтому positionFromLeft является правильным без корректировки на единицу. Этот код предполагает, с C99 или C (с незначительной оговоркой, что snprintf() не уполномочена на C 98, но скорее всего будет доступен в качестве расширения; чистого C 98 и C99 решением проблемы было бы использовать sprintf() вместо этого, который в условиях достаточно безопасно).

Протестуйте против решения, которое в свое время было выбрано как правильное!

Рассмотрим тестовый набор:

 #include <stdio.h>

int getDigit1(int value, int positionFromLeft)
{
    while (--positionFromLeft)
        value /= 10;
    return value % 10;
}

int getDigit2(int value, int positionFromLeft)
{
    char buffer[20];
    if (value > 0)
        value = -value;
    int len = snprintf(buffer, sizeof(buffer), "%d", value);
    int digit = 0;
    if (len > positionFromLeft amp;amp; positionFromLeft > 0)
        digit = buffer[positionFromLeft] - '0';
    return digit;
}

int main(void)
{
    int values[] = { 534, 1234567, -1234567 };
    for (int i = 0; i < 3; i  )
    {
        for (int j = 1; j <= 7; j  )
            printf("getDigit(%d, %d) = (v1) %d, (v2) %dn", values[i], j,
                   getDigit1(values[i], j), getDigit2(values[i], j));
        putchar('n');
    }
    return 0;
}
  

Это решение выдает правильное значение для getDigit(534, 2) и getDigit(1234567, 4) (и, как правило, среднюю цифру числа, состоящего из нечетного числа цифр), но в остальном неверно:

 getDigit(534, 1) = (v1) 4, (v2) 5
getDigit(534, 2) = (v1) 3, (v2) 3
getDigit(534, 3) = (v1) 5, (v2) 4
getDigit(534, 4) = (v1) 0, (v2) 0
getDigit(534, 5) = (v1) 0, (v2) 0
getDigit(534, 6) = (v1) 0, (v2) 0
getDigit(534, 7) = (v1) 0, (v2) 0

getDigit(1234567, 1) = (v1) 7, (v2) 1
getDigit(1234567, 2) = (v1) 6, (v2) 2
getDigit(1234567, 3) = (v1) 5, (v2) 3
getDigit(1234567, 4) = (v1) 4, (v2) 4
getDigit(1234567, 5) = (v1) 3, (v2) 5
getDigit(1234567, 6) = (v1) 2, (v2) 6
getDigit(1234567, 7) = (v1) 1, (v2) 7

getDigit(-1234567, 1) = (v1) -7, (v2) 1
getDigit(-1234567, 2) = (v1) -6, (v2) 2
getDigit(-1234567, 3) = (v1) -5, (v2) 3
getDigit(-1234567, 4) = (v1) -4, (v2) 4
getDigit(-1234567, 5) = (v1) -3, (v2) 5
getDigit(-1234567, 6) = (v1) -2, (v2) 6
getDigit(-1234567, 7) = (v1) -1, (v2) 7
  

В вопросе конкретно запрашивается N-я цифра СЛЕВА от числа, считая от 1.

Комментарии:

1. Ваш тест на отрицательное значение выполняется в обратном направлении.

2. @hammar? Это? Я хочу убедиться, что значение отрицательное, прежде чем я его отформатирую. Было две ошибки — одна синтаксическая, одна за другой, когда я менял логику, но инверсия знака верна.

3. @Jonathan: С самого начала казалось, что вы хотите положительное значение. Но таким образом она также избегает случая для INT_MIN , с которым мой код изначально потерпел неудачу. Разобраться в этих вещах, конечно, может быть непросто, да? 🙂

4. @Джонатан Леффлер : Конечно, пока вы были заняты печатанием своего протеста, ответ, о котором идет речь, был исправлен … ;-]

5. @ildjarn: да — вот почему я тщательно определил это как «в одно время»… вашей текущей версии не нравится getDigit(534, 4) и она переходит в бесконечный цикл (или, по крайней мере, цикл, который длится несколько секунд), когда ее просят вернуть 4-ю цифру из 3-значного числа. В противном случае, однако, она выдает правильные результаты.

Ответ №9:

Просто чтобы отличаться, одна без #include необходимости.

 int getDigit(unsigned int original, unsigned int positionFromLeft)
{
    if (original==0 amp;amp; positionFromLeft==1) {
        /* In a more mathematical world, zero has no digits. */
        return 0;
    }
    unsigned int expon=0;
    unsigned int power=1;
    for (unsigned int quotient=original; quotient; quotient/=10,   expon) {
        if (expon >= positionFromLeft) {
            power *= 10;
        }
    }
    if (positionFromLeft > expon) {
        /* Not enough digits in number. */
        return -1;
    }
    return (original / power) % 10;
}
  

Комментарии:

1. Я попробовал это в своем тестовом наборе — см. Мой ответ — и получил getDigit(534, 3) = -1 и getDigit(1234567, 7) = -1; остальные значения были правильными. Вероятно, вам нужно ‘>’ вместо ‘>=’ в тесте ‘недостаточно цифр’.

2. @Jonathan Спасибо. Исправлено. Очевидно, мне следовало провести больше модульного тестирования.

3. Возможно, вам захочется протестировать отрицательные числа … getDigit(-1234567, x) интересен.

4. Я специально изменил типы параметров на беззнаковые. Или, конечно, вы могли бы сделать как некоторые решения и исправить все входные данные на неотрицательные в качестве первого шага.

5. В одном аргументе говорится «проблема, о которой просили, int не unsigned int «, но это «устраняет» проблему с отрицательным значением (хотя отрицательные числа имеют N-ю цифру слева). Отрицание INT_MIN на положительное число требует использования целочисленного типа, большего, чем int (на машине с дополнением 2). Отрицание INT_MAX до отрицательного числа отлично работает на машинах дополнения 1, дополнения 2 и знаковой величины.

Ответ №10:

Поправьте меня, если я ошибаюсь.

Вы можете попробовать использовать sprintf для преобразования int в строковое представление. Затем пусть указатель (скажем, *ptr) указывает на первую позицию.

Пусть positionFromLeft будет позицией символа, который вы хотите извлечь.

Используя,

*(ptr positionFromLeft)

выдаст вам требуемую цифру. Надеюсь, это поможет.

Ответ №11:

Я думаю, что это самое простое решение:

    int valuePosition(int value, int position) {
     int r;
     for(int i=0; i<=position; i  ){
       r = value % 10;
       value = value / 10;
     }
     return r;
   }
  

Первая позиция равна 0, если вы хотите, чтобы она начиналась с 1, измените i<=position на 1

Ответ №12:

Добавьте к классу Number метод экземпляра с именем getDigit со следующей подписью: int getDigit (int digitNum) Когда переменная digitNum указывает цифру (0) для серии единиц, 1 для десятичной цифры и так далее. Метод вернет соответствующую цифру, если такая цифра существует. В противном случае метод вернет .-1 .-1 вернет digitNum = 6, а для 4 вернет метод digitNN = 3 для: значение = 124571, если, чтобы

Элемент списка