2010-06-25 55 views
17

比方说,我有一个名为“得分”的整,看起来像这样:获取每个个体的数字从整个整数

int score = 1529587; 

现在我想要做的就是让每个数字1,5,2,使用按位运算符(请参阅下面的编辑注释)得分 中的9,5,8,7。

我敢肯定,这可以完成,因为我曾经使用过类似的方法从十六进制颜色值中提取红色的绿色和蓝色值。

我该怎么做?

编辑
它不一定必须位运算符,我只是觉得这一定是简单的方式。

+1

因为我没有在我的个人位运算符汇编中找到它(http://graphics.stanford.edu/~seander/bithacks.html ),如果没有更深入的阐述,我认为这是不可能的。 – phimuemue 2010-06-25 13:49:53

+0

如果它们是十进制的,你不能使用按位来获取它们。如果它们是十六进制的,那么它是可能的。请明确说明。 – Andrey 2010-06-25 13:52:09

回答

32

您使用模运算符:

while(score) 
{ 
    printf("%d\n", score % 10); 
    score /= 10; 
} 

注意,这会给你以相反的顺序位数(即至少显著位在先)。如果您首先需要最重要的数字,则必须将数字存储在数组中,然后以相反的顺序读出数字。

+0

我很确定modulo不是一个按位运算符 – 2010-06-25 13:48:37

+1

@ Scorpi0:不,它不是......但没有明智的方法来使用按位运算符来做到这一点,我认为这是OP所寻找的。 – 2010-06-25 13:49:28

+0

我认为OP意味着十六进制,并且可以按位解决。 – Andrey 2010-06-25 13:52:53

4

RGB值在位边界上很好地下降;十进制数字不。我不认为有一个简单的方法来使用按位运算符。你需要使用十进制运算符,如模10(%10)。

+1

+1他是对的,十进制(基数为10)的数字不会在位(基2)上分割,除了2的幂数(例如256 = 2^8的颜色)。由于10不是2的幂,所以您将无法使用按位运算符。 – Geoff 2010-06-25 13:49:42

4

同意以前的答案。

稍作修改:有一种更好的方法可以从左向右打印十进制数字,而不需要分配额外的缓冲区。另外,如果score为0(以前的答案中建议的循环不会打印任何语句),则可能需要显示零字符。

这需要一个额外的传球:

int div; 
for (div = 1; div <= score; div *= 10) 
    ; 

do 
{ 
    div /= 10; 
    printf("%d\n", score/div); 
    score %= div; 
} while (score); 
+1

当'score'为零时,此解决方案会导致零除。 – Shepmaster 2017-01-08 19:58:14

+0

当解析度> = ceil(INT_MAX/10.0)时,此解决方案也会因溢出而失败。我已经提供了一个解决方案,可以对整个范围[0,UINT_MAX]进行修正。 – 2017-06-14 07:01:57

+0

此解决方案也适用于最不重要位置或位置上有0位数字的任何数字。这些零不打印。我提供的更正解决方案也避免了这个问题。 – 2017-06-15 20:08:49

2

不要推倒重来。 C有sprintf是有原因的。由于你的变量被称为分数,我猜这是针对你计划使用分数的个别数字来将数字字形显示为图像的游戏。在这种情况下,sprintf具有方便的格式修饰符,可让您将零点填充,空格键等分数固定为一个固定的宽度,您可能需要使用它。

+0

我喜欢你的分析方式,我非常感谢! – 2010-06-26 08:02:32

0

通常,使用循环中的数字模或将数字转换为字符串可以解决此问题。为了将一个数字转换为一个字符串,你可以使用函数itoa,所以考虑循环中一个数字模的变体。


内容的文件get_digits.c

$ cat get_digits.c 

#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 


// return a length of integer 
unsigned long int get_number_count_digits(long int number); 

// get digits from an integer number into an array 
int number_get_digits(long int number, int **digits, unsigned int *len); 

// for demo features 
void demo_number_get_digits(long int number); 


int 
main() 
{ 
    demo_number_get_digits(-9999999999999); 
    demo_number_get_digits(-10000000000); 
    demo_number_get_digits(-1000); 
    demo_number_get_digits(-9); 
    demo_number_get_digits(0); 
    demo_number_get_digits(9); 
    demo_number_get_digits(1000); 
    demo_number_get_digits(10000000000); 
    demo_number_get_digits(9999999999999); 
    return EXIT_SUCCESS; 
} 


unsigned long int 
get_number_count_digits(long int number) 
{ 
    if (number < 0) 
     number = llabs(number); 
    else if (number == 0) 
     return 1; 

    if (number < 999999999999997) 
     return floor(log10(number)) + 1; 

    unsigned long int count = 0; 
    while (number > 0) { 
     ++count; 
     number /= 10; 
    } 
    return count; 
} 


int 
number_get_digits(long int number, int **digits, unsigned int *len) 
{ 
    number = labs(number); 

    // termination count digits and size of a array as well as 
    *len = get_number_count_digits(number); 

    *digits = realloc(*digits, *len * sizeof(int)); 

    // fill up the array 
    unsigned int index = 0; 
    while (number > 0) { 
     (*digits)[index] = (int)(number % 10); 
     number /= 10; 
     ++index; 
    } 

    // reverse the array 
    unsigned long int i = 0, half_len = (*len/2); 
    int swap; 
    while (i < half_len) { 
     swap = (*digits)[i]; 
     (*digits)[i] = (*digits)[*len - i - 1]; 
     (*digits)[*len - i - 1] = swap; 
     ++i; 
    } 

    return 0; 
} 


void 
demo_number_get_digits(long int number) 
{ 
    int *digits; 
    unsigned int len; 

    digits = malloc(sizeof(int)); 

    number_get_digits(number, &digits, &len); 

    printf("%ld --> [", number); 
    for (unsigned int i = 0; i < len; ++i) { 
     if (i == len - 1) 
      printf("%d", digits[i]); 
     else 
      printf("%d, ", digits[i]); 
    } 
    printf("]\n"); 

    free(digits); 
} 

演示与GNU GCC

$~/Downloads/temp$ cc -Wall -Wextra -std=c11 -o run get_digits.c -lm 
$~/Downloads/temp$ ./run 
-9999999999999 --> [9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9] 
-10000000000 --> [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 
-1000 --> [1, 0, 0, 0] 
-9 --> [9] 
0 --> [0] 
9 --> [9] 
1000 --> [1, 0, 0, 0] 
10000000000 --> [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 
9999999999999 --> [9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9] 

演示与LLVM /锵

$~/Downloads/temp$ rm run 
$~/Downloads/temp$ clang -std=c11 -Wall -Wextra get_digits.c -o run -lm 
setivolkylany$~/Downloads/temp$ ./run 
-9999999999999 --> [9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9] 
-10000000000 --> [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 
-1000 --> [1, 0, 0, 0] 
-9 --> [9] 
0 --> [0] 
9 --> [9] 
1000 --> [1, 0, 0, 0] 
10000000000 --> [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 
9999999999999 --> [9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9] 

测试环境

$~/Downloads/temp$ cc --version | head -n 1 
cc (Debian 4.9.2-10) 4.9.2 
$~/Downloads/temp$ clang --version 
Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0) 
Target: x86_64-pc-linux-gnu 
Thread model: posix 
1

这种解决方案使在整个范围上正确的结果[0,UINT_MAX] ,而不需要数字来进行缓冲。

它也适用于适当类型更改的更宽类型或带符号类型(带正值)。

这种方法在微小的环境下(如Arduino引导程序)特别有用,因为它不会导致所有的printf()膨胀(当printf()没有用于演示输出时)并且使用非常小内存。你可以通过闪烁一个单一的LED看看价值:)

#include <limits.h> 
#include <stdio.h> 

int 
main (void) 
{ 
    unsigned int score = 42; // Works for score in [0, UINT_MAX] 

    printf ("score via printf:  %u\n", score); // For validation 

    printf ("score digit by digit: "); 
    unsigned int div = 1; 
    unsigned int digit_count = 1; 
    while (div <= score/10) { 
    digit_count++; 
    div *= 10; 
    } 
    while (digit_count > 0) { 
    printf ("%d", score/div); 
    score %= div; 
    div /= 10; 
    digit_count--; 
    } 
    printf ("\n"); 

    return 0; 
}