开发者

A function that returns a digit within a number

I want to create a function which will a number and the position of the digit that I wan开发者_如何学JAVAt to retrieve,

int getDigit(int value, int positionFromLeft)

Say, getDigit(534, 2) will return 3.

What could be the easiest / efficient way to write this function?


First, it'll be a lot easier if you're willing to work for the right instead of the left (i.e., from the least significant digit).

Given an input N, N%10 will give the least significant digit. X/10 will shift X one digit to the right, x/100 will shift it two digits to the right, etc.

If you really need to start from the left, log10 should get you the total number of digits.


All these string-based solutions scare me... Really guys? :-/

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;
}

Note that passing an out-of-bounds value for positionFromLeft won't return any sensical value as-is.


The easiest is just to convert to a string and do a lookup. This example uses C++, but the idea can easily be translated to C.

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

    std::stringstream ss;
    ss << value;

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

Turns out there are some corner cases to think about here.

  • What happens if value is negative? I chose to ignore the sign and count from the first digit.
  • What if the position is out of bounds? I chose to throw an exception.
  • There is also a possibility of value being INT_MIN, so simply taking the absolute value won't work.


Different recursive solution to this old question (I changed the type of positionFromLeft to 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);
}

See ideone


Simplest but not necessarily the best:

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';
}

Note: Edited since someone objected (apparently) to snprintf not being in C++, and to account for out-of-bounds and one-based position. Now it's slightly less simple...


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

with @R..'s suggestion:

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

Hope this helps! This is a nice little C++ refresher for me :)


If you really need to count from left, you can do this:

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;
}

But this is probably not really more efficient or easier than string solutions, but since it is homework, there might be a few algebraic things to learn if not done with strings :)

However, you need less stack space.


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 && positionFromLeft > 0)
        digit = buffer[positionFromLeft] - '0';
    return digit;
}

This returns zero if you ask for a digit beyond the RHS of the number. The negation trick ensures that the value is always negative (and never runs into problems with negating INT_MIN), and then there is a minus sign so the positionFromLeft is correct without adjusting by one. This code assumes C99 or C++ (with the minor caveat that snprintf() is not mandated by C++98 but is likely to be available as an extension; a pure C++98 and C99 solution would have to use sprintf() instead, which in context is safe enough).

Protest over the solution that was at one time selected as correct!

Consider the test harness:

#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 && 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) %d\n", values[i], j,
                   getDigit1(values[i], j), getDigit2(values[i], j));
        putchar('\n');
    }
    return 0;
}

This solution produces the correct value for getDigit(534, 2) and getDigit(1234567, 4) (and, generally, the middle digit of a number that has an odd number of digits) but is otherwise incorrect:

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

The question specifically asks for the Nth digit from the LEFT of the number, counting from 1.


Just to be different, one with no #include needed.

int getDigit(unsigned int original, unsigned int positionFromLeft)
{
    if (original==0 && 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;
}


Correct me if i am wrong.

You can try using sprintf to cast the int to a string representations. Then have a pointer (say *ptr) point to the first position.

Let positionFromLeft be the position of the character that you want to extract.

Using,

*(ptr + positionFromLeft)

will give you the required digit. Hope that helps.


I think this is the easiest solution:

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

The first position is 0, if you want that starts in 1 change i<=position with 1


Add to the Number class an instance method called getDigit with the following signature: int getDigit (int digitNum) When the digitNum variable specifies the digit number (0) for the unity series, 1 for the tens digit And so on. The method will return the appropriate digit if such a digit exists. Otherwise the method will return .-1 .-1 will return digitNum = 6 and for 4 return the digitNN = 3 method for: value = 124571 if, to

List item

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜