【问题标题】:Issue with long long calculation长长计算的问题
【发布时间】:2016-06-30 15:38:13
【问题描述】:

我的代码循环遍历数字并创建该整数的字符数组表示。所以对于像 1234 这样的数字,我得到一个看起来像 {'1', '2', '3', '4'}

部分代码如下:

do {
   //print here
     c[i++] = (char)(((int)'0')+(num - (num/10)*10 ));
} while ((num = num/10) != 0);

当涉及到 long long int 等大型数据类型时,我遇到了问题:18446612134627563776

我在循环中打印的值是:

18446612134627563776
18446730879801352832
18446742754318731738
...
18446744073709551615

值应该是

18446612134627563776
1844661213462756377
184466121346275637
...
18
1

奇怪的是循环终止了。最后打印的值是18446744073709551615 != 0,所以不确定它为什么会在那里终止。我认为这是我做得不对的数据类型的一些问题。

这是打印语句:

printk("long=%llu sec=%llu , char=%c\n", num, (num/10)*10, (char)(((int)'0')+((num - (num/10)*10 ))));

【问题讨论】:

  • 您是否检查过您的数字的大小与旨在容纳它们的数据类型的最大大小?
  • (num/10)*10 有什么意义?
  • 这是num - (num % 10), @Zaffy 的另一种写法。
  • 如上图的数字大小为20位。当我打印 sizeof(long long) 我得到 8,我猜是 8 个字节?
  • @DanielFischer num - (num % 10) 不起作用,我正在尝试下面的地板方法。

标签: c


【解决方案1】:

您的代码很好。问题是num 的类型是签名的(即只是long long)。将其更改为 (unsigned long long) 就可以了。

【讨论】:

    【解决方案2】:

    long long int: 18446612134627563776

    long long int是有符号类型,通常是64位宽,有最大可表示数

    2^63-1 = 9223372036854775807
    

    你的值大于那个值,并且溢出,可能到

    2^63 - 18446612134627563776 = -131939081987840
    

    打印出来的值是

    2^64 + (-131939081987840)/(10^k)
    

    将类型改为unsigned long long即可得到预期的结果。

    【讨论】:

      【解决方案3】:

      为什么不使用模运算符来计算除法的余数以获得最后一位?

      下面的整数

      do {
          c[i++] = (char)(((int)'0')+(num %10 ));
      } while ((num = (num/10)) != 0);
      

      【讨论】:

      • 在 C++ 中,整数类型的除法总是向零舍入。不要使用floor,除非你需要它来进行浮点运算(即使那样,它也可能很棘手)。
      • 哦,好吧,我不确定,他使用的是 C 而不是 C++
      • 是的,我刚刚移除了地板,因为@aschepler 说这不是强制性的
      • 这不仅不是强制性的,在整数计算中也没有任何意义。编译器会将整数参数转换为浮点参数,将其传递给 floor(),结果将是浮点数,编译器会将其转换回整数,然后再将其分配给整数变量。您应该得到完全相同的结果,除非您的原始整数值的位宽大于浮点类型的尾数位宽,在这种情况下,您现在将得到错误的结果。
      • 而且它与 C 与 C++ 无关。
      【解决方案4】:

      不是溢出,我用这段代码测试过。

      unsigned long long num = 18446612134627563776;
      char c[100];
      unsigned int i = 0;
      
      do {
          //print here
          c[i++] = '0'+ (char)(num - (num/10)*10 );
      } while ((num = num/10) != 0);
      
      c[i] = '\0';
      cout << c << endl;
      

      问题是编译器可能试图将 10 用作 int,并且在转换时遇到问题。放入铸件后,它确实有效。问题是算法是倒退的,因为它会引入 6,然后是 7,等等...输出如下,与他的代码完全相同,除了强制转换。

      这是实际代码,也是实际输出。

      677365726431221664481
      

      希望这会有所帮助:-)

      【讨论】:

      • 将 10 转换为 unsigned long long 只会使编译器在计算之前将 num 提升为 unsigned long long。因此,本质上,您正在做与将num 的类型更改为无符号的“相同的事情”,但是方式错误。编译器没有“转换有问题”...它完全根据提升规则进行转换。
      • @phonetagger - 你是对的,我疲惫的头脑刚刚意识到这一点。 :-) 但是它仍然会倒退。我宣传了你的答案,哈哈。
      猜你喜欢
      • 2015-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多