1

有没有一种优雅的方法来截断左方向小数或与基数无关的整数?

例如我有:

unsigned int val1 = 17301;

该算法必须通过一次调用从左侧截断 1(十进制)数字,因此对于 val1,4 次调用的结果将是:

truncate_left(17301) returns 7301
truncate_left(7301) returns 301
truncate_left(301) returns 1
truncate_left(1) returns 0

返回值也是整数。c/c++ 解决方案最适合我。任何外部(和/或)数学库都不受欢迎,我对通用方式感兴趣

@ATaylor 我丑陋的解决方案是:

unsigned int truncate_left(unsigned int val) {
  unsigned int divider = 1000000000, dec;
  for(unsigned int pow10 = 10; pow10 > 0; pow10--) {
    if(val % divider != val) {
      dec = val / divider;
      printf("dec = %d\n", divider);
      break;
    }
    divider /= 10;
  }
  return val - dec * divider;
}

谢谢!

4

7 回答 7

5

我不确定为什么@MM 删除了他几乎就在那里的答案,但这是它的更正版本:

int truncate_left(int x)
{
    int c = (int)log10(x);
    while (x > pow(10,c)) x -= pow(10,c);
    return x;
}

如果使用 math.h 和 -lm 有问题,请将 log10 和 pow 替换为:

int mylog10(int val)
{
   if (val > 9) return 1 + mylog10(val/10);
   return 1;
}

int mypow(int val, int pwr)
{
    if (pwr > 0) return val * mypow(val, pwr-1);
    return val;
}
于 2013-04-23T11:38:07.343 回答
3

这是一种解决方法,但它应该做你想做的(虽然我看不出你为什么想要它)

无论如何,首先,您需要确定哪个数字是最左边的数字。

为此,您需要知道底数(您确实知道,对吗?)一旦您知道最左边的数字,您需要用它的位置乘以底数减去这个确切的数字......你就完成了。

这是有关如何完成此操作的代码片段。虽然未经测试。

int truncate_left(int val, int base) {    
    int Multiplier = 1, LeftDigit = val;
    while(LeftDigit > base) {
        LeftDigit /= base;
        Multiplier *= base;
    }
    return val - (LeftDigit * Multiplier);
}

为了处理负数,我们需要添加一些额外的东西。

int truncate_left(int val, int base) {
    bool isNegative = (val < 0);
    int Multiplier = 1, LeftDigit = val;
    if(isNegative) LeftDigit *= -1;
    while(LeftDigit > base) {
        LeftDigit /= base;
        Multiplier *= base;
    }
    if(isNegative) LeftDigit *= -1;
    return val - (LeftDigit * Multiplier);
}

标志会记住,如果数字一isNegative开始是负数并且为了我们的方便而存在(我们也可以检查val < 0两次)。它变为LeftDigit正数(它是“绝对值”,确定乘数,然后将其变为负数。

由于val是负数,我们从中减去另一个负值(-LeftDigit * Multiplier),它等于+,导致正确的结果并保留符号。

于 2013-04-23T11:34:23.063 回答
3

如果字符串没有作弊:

int truncate_left(int i) {
    return std::stoi(std::to_string(i).substr(1));
}
于 2013-04-23T11:38:42.050 回答
2

我刚刚写了:

int truncate_left(int x)
{
  int c = (int)log10(x);   // c: digits - 1
  int p = pow(10,c);       // p: 10 ^ c
  int k = x / p;           // k: leftmost non-zero digit
  return x - k * p;
}

注:x应大于零。

于 2013-04-23T11:30:58.853 回答
2

没有捷径可走。您必须将 17301 写为 10000 + 7301。很明显 truncate_left 返回 7301 部分。剩下的就是找出 10000 部分,您可以从“打印数字”代码示例中删除它。

于 2013-04-23T11:35:18.347 回答
1

也检查一下这个,

unsigned int tru(unsigned int a)
{
unsigned int b = a,c=0;

while(b!=0)
{
 c++;
 b /=10;
}

cout<<"length: "<<c<<endl;

int mul= 1;
c--;

while(c)
{
 mul *= 10;
 c--;
}

cout<<"mul is "<<mul<<endl;

return a%mul;
}
于 2013-04-23T12:02:54.933 回答
1
unsigned truncate_left_aux(unsigned n, unsigned sum, unsigned base){
    unsigned nn;
    return (0==(nn=n/10))? sum : truncate_left_aux(nn, sum + (n % 10) * base, 10*base);
}

unsigned truncate_left(unsigned n){
    truncate_left_aux(n, 0, 1);
}
于 2013-04-23T12:08:50.600 回答