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
beingINT_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
精彩评论