Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/63.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 有没有更有效的方法将一个数字拆分成数字?_C_Performance_Digits - Fatal编程技术网

C 有没有更有效的方法将一个数字拆分成数字?

C 有没有更有效的方法将一个数字拆分成数字?,c,performance,digits,C,Performance,Digits,为了在LCD上显示,我必须将一个数字拆分成数字。现在我使用以下方法: pos = 7; do { LCD_Display(pos, val % 10); val /= 10; pos--; } while (pos >= 0 && val); 这种方法的问题是在MSP430微控制器上除法和模运算速度非常慢。除了这种方法之外,还有什么替代方法,不涉及除法或减少运算次数的方法吗 注意:我不能使用任何库函数,例如itoa。库很大,函数本身也非常需要资源

为了在LCD上显示,我必须将一个数字拆分成数字。现在我使用以下方法:

pos = 7;

do
{
    LCD_Display(pos, val % 10);
    val /= 10;
    pos--;
} while (pos >= 0 && val);
这种方法的问题是在MSP430微控制器上除法和模运算速度非常慢。除了这种方法之外,还有什么替代方法,不涉及除法或减少运算次数的方法吗


注意:我不能使用任何库函数,例如
itoa
。库很大,函数本身也非常需要资源(无论是在周期数还是RAM使用方面)。

您可以使用预定义的基10值在循环中进行减法运算

我的C有点生锈,但有点像这样:

int num[] = { 10000000,1000000,100000,10000,1000,100,10,1 };

for (pos = 0; pos < 8; pos++) {
  int cnt = 0;
  while (val >= num[pos]) {
    cnt++;
    val -= num[pos];
  }
  LCD_Display(pos, cnt);
}
#include <stdio.h>

// here are our scaled factors
static const unsigned long long factors[] = { 
    3435973837,  // ceil((0.1 * 2**32)<<3)
    2748779070,  // ceil((0.01 * 2**32)<<6)
    2199023256,  // etc.
    3518437209,
    2814749768,
    2251799814,
    3602879702,
    2882303762,
    2305843010
};

static const char shifts[] = {
    3, // the shift value used for each factor above
    6,
    9,
    13,
    16,
    19,
    23,
    26,
    29
};

int main() { 
    unsigned input = 13754;

    for (int i=8; i!=-1; i--) {
        unsigned long long inter = input * factors[i];
        inter >>= shifts[i];
        inter &= (unsigned)-1;
        inter *= 10;
        inter >>= 32;
        printf("%u", inter);
    }
    return 0;
}
int num[]={1000000100001000001000001000100,10,1};
用于(pos=0;pos<8;pos++){
int-cnt=0;
而(val>=num[pos]){
cnt++;
val-=num[pos];
}
液晶显示器(pos、cnt);
}

我会使用一个临时字符串,如:

char buffer[8];
itoa(yourValue, buffer, 10);
int pos;

for(pos=0; pos<8; ++pos)
    LCD_Display(pos, buffer[pos]); /* maybe you'll need a cast here */
char缓冲区[8];
itoa(你的值,缓冲区,10);
int pos;
对于(pos=0;pos是的,有,最初由Terje Mathiesen发明(至少是AFAIK),而不是除以10,你(有点)乘以倒数。当然,诀窍在于,在整数中,不能直接表示倒数。为了弥补这一点,你可以使用缩放整数。如果我们有浮点,我们可以用如下方式提取数字:

input = 123

first digit = integer(10 * (fraction(input * .1))
second digit = integer(100 * (fraction(input * .01))
    mov ebx, 9 ; maximum digits we can deal with.
    mov esi, offset output_buffer
next_digit:
    mov eax, input
    mul factors[ebx*4]
    mov cl, shifts[ebx]
    shrd eax, edx, cl
    mov edx, 10 ; overwrite edx => inter &= (unsigned)-1
    mul edx 
    add dl, '0'
    mov [esi], dl ; effectively shift right 32 bits by ignoring 32 LSBs in eax
    inc esi
    dec ebx
    jnz next_digit
    mov [esi], bl ; zero terminate the string
…以此类推,以获得所需的任意多个数字。要对整数执行此操作,我们基本上只需将它们按232进行缩放(并对每个整数进行取整,因为我们将使用截断数学)。在C中,算法如下所示:

int num[] = { 10000000,1000000,100000,10000,1000,100,10,1 };

for (pos = 0; pos < 8; pos++) {
  int cnt = 0;
  while (val >= num[pos]) {
    cnt++;
    val -= num[pos];
  }
  LCD_Display(pos, cnt);
}
#include <stdio.h>

// here are our scaled factors
static const unsigned long long factors[] = { 
    3435973837,  // ceil((0.1 * 2**32)<<3)
    2748779070,  // ceil((0.01 * 2**32)<<6)
    2199023256,  // etc.
    3518437209,
    2814749768,
    2251799814,
    3602879702,
    2882303762,
    2305843010
};

static const char shifts[] = {
    3, // the shift value used for each factor above
    6,
    9,
    13,
    16,
    19,
    23,
    26,
    29
};

int main() { 
    unsigned input = 13754;

    for (int i=8; i!=-1; i--) {
        unsigned long long inter = input * factors[i];
        inter >>= shifts[i];
        inter &= (unsigned)-1;
        inter *= 10;
        inter >>= 32;
        printf("%u", inter);
    }
    return 0;
}
目前,我已经做了一点欺骗,并在每个表的开头假设一个额外的项(
factors
shift
)来编写代码。这不是严格必要的,但以浪费8字节数据为代价简化了代码。这也很容易消除,但我暂时还没有费心


无论如何,在许多缺乏专用除法硬件的中低端处理器上,取消除法会使除法速度大大加快。

这是我尝试的一个完整解决方案。Guffa提供了总体思路,这应该归功于Guffa。这应该适用于32位整数,有符号或其他形式,以及0

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

#define MAX_WIDTH (10)

static unsigned int uiPosition[] = {
  1u,
  10u,
  100u,
  1000u,
  10000u,
  100000u,
  1000000u,
  10000000u,
  100000000u,
  1000000000u,
};

void uitostr(unsigned int uiSource, char* cTarget)
{
  int i, c=0;

  for( i=0; i!=MAX_WIDTH; ++i )
  {
    cTarget[i] = 0;
  }

  if( uiSource == 0 )
  {
    cTarget[0] = '0';
    cTarget[1] = '\0';
    return;
  }

  for( i=MAX_WIDTH -1; i>=0; --i )
  {
    while( uiSource >= uiPosition[i] )
    {
      cTarget[c] += 1;
      uiSource -= uiPosition[i];
    }

    if( c != 0 || cTarget[c] != 0 )
    {
      cTarget[c] += 0x30;
      c++;
    }
  }

  cTarget[c] = '\0';
}

void itostr(int iSource, char* cTarget)
{
  if( iSource < 0 )
  {
    cTarget[0] = '-';
    uitostr((unsigned int)(iSource * -1), cTarget + 1);
  }
  else
  {
    uitostr((unsigned int)iSource, cTarget);
  }
}

int main()
{
  char szStr[MAX_WIDTH +1] = { 0 };

  // signed integer
  printf("Signed integer\n");

  printf("int: %d\n", 100);
  itostr(100, szStr);
  printf("str: %s\n", szStr);

  printf("int: %d\n", -1);
  itostr(-1, szStr);
  printf("str: %s\n", szStr);

  printf("int: %d\n", 1000000000);
  itostr(1000000000, szStr);
  printf("str: %s\n", szStr);

  printf("int: %d\n", 0);
  itostr(0, szStr);
  printf("str: %s\n", szStr);

  return 0;
}
#包括
#包括
#定义最大宽度(10)
静态无符号整数uiPosition[]={
1u,
10u,
100u,
1000u,
10000美元,
100000 U,
一百万,
1亿美元,
100000000美元,
100000000美元,
};
void uitostr(未签名的int uiSource,char*cTarget)
{
int i,c=0;
对于(i=0;i!=最大宽度;++i)
{
cTarget[i]=0;
}
如果(uiSource==0)
{
cTarget[0]=“0”;
cTarget[1]='\0';
返回;
}
对于(i=最大宽度-1;i>=0;--i)
{
而(uiSource>=uiPosition[i])
{
cTarget[c]+=1;
uiSource-=uiPosition[i];
}
如果(c!=0 | | cTarget[c]!=0)
{
cTarget[c]+=0x30;
C++;
}
}
cTarget[c]='\0';
}
void itostr(int-isosource,char*cTarget)
{
如果(iSource<0)
{
cTarget[0]='-';
uitostr((无符号整数)(iSource*-1),cTarget+1);
}
其他的
{
uitostr((无符号整数)iSource,cTarget);
}
}
int main()
{
char szStr[MAX_WIDTH+1]={0};
//有符号整数
printf(“有符号整数”);
printf(“int:%d\n”,100);
itostr(100,szStr);
printf(“str:%s\n”,szStr);
printf(“int:%d\n”,-1);
itostr(-1,szStr);
printf(“str:%s\n”,szStr);
printf(“int:%d\n”,100000000);
itostr(1000000000,szStr);
printf(“str:%s\n”,szStr);
printf(“int:%d\n”,0);
itostr(0,szStr);
printf(“str:%s\n”,szStr);
返回0;
}

另一种方法是使用。这是一种将二进制转换为BCD的方法,只需进行加法和位移位,因此非常适合微控制器。拆分为BCD后,您可以轻松打印出每个数字

这可能看起来像是一种微优化,但我编写的示例代码大约需要2.5ms,如果您使用batt,则会很长时间有些编译器能够将除法和模优化为乘法和移位。你使用的是什么编译器和什么优化?Basile:没错。如果你使用一些最近启用优化的gcc(类似-O2标志),这应该是优化的。我现在正在使用IAR,优化设置为低(尽管它对本部分代码没有影响)除法需要很长的时间,特别是当val是一个uint32_t时。每个操作大约需要450个周期。另外,请看这个:有趣的想法。我会研究一下,看看执行时间是否有差异。谢谢!它是有效的。执行时间已从~2.1ms下降到小于700us。您应该将num声明为const,因为它是一个constnt查找表。除了“const正确性”的好处之外,这也可能使代码在某些平台上更有效。@Lundin肯定!num数组在使用它的文件中应该是一个
静态常量
。@alex将static关键字与const一起使用是一种可以讨论的做法。因为在文件范围内声明const表变量最有意义,所以它们将得到静态存储默认情况下为e duration。此外,这完全取决于const是否应该从多个文件中访问,或者它是否应该仅由当前文件使用。在C中,const变量是少数几个可以使用全局变量的情况之一,因为没有外部调用程序可以更改其内容以实现意大利面代码。我不能使用任何库函数s、 它们占用了大量的代码空间,而且通常非常消耗资源。虽然我没有机会在实际的开发板上试用它,但它仍然有效。谢谢你!@alex:稍微看一看,我不太确定它在这种情况下会有多好。MSP430显然没有乘法指令,我认为这是错误的It’这可能会有点伤脑筋。