【问题标题】:Unexpected modulo behavior with long integers长整数的意外模数行为
【发布时间】:2017-04-28 18:37:42
【问题描述】:

当操作数为(un)signedlong 时,C++ 的模% 运算符的行为很奇怪。

为什么mod(signed int, unsigned int)mod(signed long long int, unsigned long long int) 会产生不同的结果?如果我想要正确的一个(这里:11183)怎么办?

注意:如果我按照我的算法,我应该打电话给uint64_t mod(int64_t, uint64_t)

// Tip: 11183 is the "correct" expected result.

(                   int)(-3365) % (                   int)(15156) = -3365
(  signed           int)(-3365) % (  signed           int)(15156) = -3365
(unsigned           int)(-3365) % (unsigned           int)(15156) = 11183
(  signed           int)(-3365) % (unsigned           int)(15156) = 11183
(unsigned           int)(-3365) % (  signed           int)(15156) = 11183

(              long int)(-3365) % (              long int)(15156) = -3365
(  signed      long int)(-3365) % (  signed      long int)(15156) = -3365
(unsigned      long int)(-3365) % (unsigned      long int)(15156) = 2555
(  signed      long int)(-3365) % (unsigned      long int)(15156) = 2555
(unsigned      long int)(-3365) % (  signed      long int)(15156) = 2555

(         long long int)(-3365) % (         long long int)(15156) = -3365
(  signed long long int)(-3365) % (  signed long long int)(15156) = -3365
(unsigned long long int)(-3365) % (unsigned long long int)(15156) = 2555
(  signed long long int)(-3365) % (unsigned long long int)(15156) = 2555
(unsigned long long int)(-3365) % (  signed long long int)(15156) = 2555

(          int_fast16_t)(-3365) % (          int_fast16_t)(15156) = -3365
(         uint_fast16_t)(-3365) % (          int_fast16_t)(15156) = 2555
(          int_fast16_t)(-3365) % (         uint_fast16_t)(15156) = 2555
(         uint_fast16_t)(-3365) % (         uint_fast16_t)(15156) = 2555

(          int_fast32_t)(-3365) % (          int_fast32_t)(15156) = -3365
(         uint_fast32_t)(-3365) % (          int_fast32_t)(15156) = 2555
(          int_fast32_t)(-3365) % (         uint_fast32_t)(15156) = 2555
(         uint_fast32_t)(-3365) % (         uint_fast32_t)(15156) = 2555

(          int_fast64_t)(-3365) % (          int_fast64_t)(15156) = -3365
(         uint_fast64_t)(-3365) % (          int_fast64_t)(15156) = 2555
(          int_fast64_t)(-3365) % (         uint_fast64_t)(15156) = 2555
(         uint_fast64_t)(-3365) % (         uint_fast64_t)(15156) = 2555

PS:关于我的系统的更多信息:

Linux pc-gi-446 4.4.0-36-generic #55-Ubuntu SMP x86_64 x86_64 x86_64 GNU/Linux
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609

【问题讨论】:

  • 你为什么不调查一下(uint64_t) -3365的值是什么?我们就叫它val;那么你还在为计算val % 15156会发生什么感到惊讶吗?
  • 无符号类型不代表负值。当负整数转换为无符号类型时,模运算恰好在该无符号类型的范围内产生一个非负值。然后,当您应用自己的模数时,这是在该模数之上的第二个模数。应用于原始值的模运算使用 (1 + MAX) 的模数,其中 MAX 是该无符号类型的最大值。例如(unsigned int) -3 导致-3 减少到以ULONG_MAX + 1 为模的最小正值,从而得到值ULONG_MAX - 2

标签: c++ long-integer modulo


【解决方案1】:

试试

unsigned int x = -3365; printf("%u", x);

它不会打印“3365”,但会打印无符号整数减去 3365 + 1 的最大值,即UINT_MAX-3365+1,即4294963931

所以(unsigned int)(-3365) % (unsigned int)(15156)unsigned int z = 4294963931 % 15156; printf("%u\n", z) 相同,并给出11183

【讨论】:

    【解决方案2】:

    % 不是

    另见What's the difference between “mod” and “remainder”?,这里也适用的 C 答案。


    在 C++ 中,% 是除法的余数-3365/15156 --> 0。除法的余数是-3365。

    (int)(-3365) % (int)(15156) = -3365  
    

    以下内容起初看起来是错误的,但由于转换为 unsigned 数学,它是正确的

    (unsigned long int)(-3365) % (unsigned long int)(15156) = 2555
    (ULONG_MAX + 1 -3365) % 15156 = 2555
    

    【讨论】:

    • 为什么 mod(signed int, unsigned int) 和 mod(signed long long int, unsigned long long int) 会产生不同的结果?
    • @Odepax 第 1 步:使用signed int % unsigned int,在% 出现之前,两个参数都转换为unsigned。使用signed long long % unsigned long long,两个参数在% 发生之前都转换为unsigned long long。为什么会发生这种情况有什么问题吗?第 2 步:第一个参数更改为什么值?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-08
    相关资源
    最近更新 更多