简体   繁体   English

如何对这个公式取模?

[英]How to modulo this formula?

I would like to write this formula in C++ language:我想用 C++ 语言写这个公式:

I would like to do this without using special structures.我想在不使用特殊结构的情况下做到这一点。 Unfortunately in this formula there are a lot of cases which effectively make modulation difficult.不幸的是,在这个公式中有很多情况会有效地使调制变得困难。 Example: ((nk)!) mod M can be equal to 0 , or ((n-1)(n-2))/4 may not be an integer.示例: ((nk)!) mod M can be equal to 0 ,或者((n-1)(n-2))/4可能不是 integer。 I will be very grateful for any help.我将非常感谢任何帮助。

The expression implies the use of a floating point type.该表达式暗示使用浮点类型。 Therefore, use the function fmod to get the remainder of the division.因此,使用 function fmod来获得除法的余数。

(n−1)./(n−k)! (n-1)./(n-k)! can be handled by computing the product (n−k+1)…(n−1).可以通过计算乘积 (n−k+1)…(n−1) 来处理。

(n−1). (n-1)。 (n−1)(n−2)/4 can be handled by handling n ≤ 2 (0) and n ≥ 3 (3…(n−1) (n−1)(n−2)/2) separately. (n−1)(n−2)/4 可以通过分别处理 n ≤ 2 (0) 和 n ≥ 3 (3…(n−1) (n−1)(n−2)/2) 来处理。

Untested C++:未经测试的 C++:

#include <cassert>
#include <cstdint>

class Residue {
public:
  // Accept int64_t for convenience.
  explicit Residue(int64_t rep, int32_t modulus) : modulus_(modulus) {
    assert(modulus > 0);
    rep_ = rep % modulus;
    if (rep_ < 0)
      rep_ += modulus;
  }

  // Return int64_t for convenience.
  int64_t rep() const { return rep_; }
  int32_t modulus() const { return modulus_; }

private:
  int32_t rep_;
  int32_t modulus_;
};

Residue operator+(Residue a, Residue b) {
  assert(a.modulus() == b.modulus());
  return Residue(a.rep() + b.rep(), a.modulus());
}

Residue operator-(Residue a, Residue b) {
  assert(a.modulus() == b.modulus());
  return Residue(a.rep() - b.rep(), a.modulus());
}

Residue operator*(Residue a, Residue b) {
  assert(a.modulus() == b.modulus());
  return Residue(a.rep() * b.rep(), a.modulus());
}

Residue QuotientOfFactorialsMod(int32_t a, int32_t b, int32_t modulus) {
  assert(modulus > 0);
  assert(b >= 0);
  assert(a >= b);
  Residue result(1, modulus);
  // Don't initialize with b + 1 because it could overflow.
  for (int32_t i = b; i < a; i++) {
    result = result * Residue(i + 1, modulus);
  }
  return result;
}

Residue FactorialMod(int32_t a, int32_t modulus) {
  assert(modulus > 0);
  assert(a >= 0);
  return QuotientOfFactorialsMod(a, 0, modulus);
}

Residue Triangular(int32_t a, int32_t modulus) {
  assert(modulus > 0);
  return Residue((static_cast<int64_t>(a) + 1) * a / 2, modulus);
}

Residue F(int32_t n, int32_t k, int32_t m) {
  assert(n >= 2);
  assert(n <= 100000);
  assert(k >= 1);
  assert(k <= n);
  assert(m >= 2);
  assert(m <= 1000000000);
  Residue n_res(n, m);
  Residue n_minus_1(n - 1, m);
  Residue n_minus_2(n - 2, m);
  Residue k_res(k, m);
  Residue q = QuotientOfFactorialsMod(n - 1, n - k, m);
  return q * (k_res - n_res) * n_minus_1 +
         (FactorialMod(n - 1, m) - q) * k_res * n_minus_1 +
         (n > 2 ? QuotientOfFactorialsMod(n - 1, 2, m) *
                      (n_res * n_minus_1 + Triangular(n - 2, m))
                : Residue(1, m));
}

方程

As mentioned in the other answer dividing factorials can be evaluated directly without division.正如其他答案中提到的那样,除法因子可以直接评估而无需除法。 Also you need 64bit arithmetics in order to store your subresults.您还需要 64 位算术来存储您的子结果。 And use modulo after each multiplication otherwise you would need very huge numbers which would take forever to compute.并在每次乘法后使用模数,否则您将需要非常庞大的数字,这将需要很长时间才能计算出来。

Also you mention ((n-1)(n-2))/4 can be non just integer how to deal with that is questionable as we do not have any context to what you are doing.您还提到((n-1)(n-2))/4可以不只是 integer 如何处理这是有问题的,因为我们没有任何关于您正在做什么的背景。 However you can move /2 before brackets (apply it on (n-1)! so modpi without 2 beware not to divide the already modded factorial!!!) and then you have no remainder as the (n-1)*(n-2)/4 become (n-1)*(n-2)/2 and the (n-1)*(n-2) is always odd (divisible by 2).但是,您可以在括号前移动/2 (将其应用于(n-1)!所以没有2modpi注意不要除已修改的阶乘!!!)然后您就没有余数了,因为(n-1)*(n-2)/4变为(n-1)*(n-2)/2并且(n-1)*(n-2)总是奇数(可被 2 整除)。 The only "problem" is when n=2 as the n*(n-1)/2 is 1 but the /2 moved before bracket will round down the (n-1)!唯一的“问题”是当n=2因为n*(n-1)/21但在括号之前移动的/2将向下舍入(n-1)! so you should handle it as special case by not moving the /2 before brackets (not included in code below).所以你应该把它作为特殊情况处理,不要在括号前移动/2 (不包括在下面的代码中)。

I see it like this:我是这样看的:

typedef unsigned __int64 u64;
u64 modpi(u64 x0,u64 x1,u64 p)  // ( x0*(x0+1)*(x0+2)*...*x1 ) mod p
    {
    u64 x,y;
    if (x0>x1){ x=x0; x0=x1; x1=x; }
    for (y=1,x=x0;x<=x1;x++){ y*=x; y%=p; }
    return y;
    }

void main()
    {
    u64 n=100,k=20,m=123456789,a,b,b2,c,y;
    
    a =modpi(n-k+1,n-1,m);      // (n-1)!/(n-k)!
    b =modpi(1,n-1,m);          // (n-1)! mod m
    b2=modpi(3,n-1,m);          // (n-1)!/2 mod m
    c =((n*(n-1)))%m;           // 2*( n*(n-1)/2 + (n-1)*(n-2)/4 ) mod m
    c+=(((n-1)*(n-2))/2)%m;
    
    y =(((a*(k-n))%m)*(n-1))%m; // ((n-1)!/(n-k)!)*(k-1)*(n-1) mod m
    y+=b;                       // (n-1)! mod m
    y-=(((a*k)%m)*(n-1))%m;     // ((n-1)!/(n-k)!)*k*(n-1) mod m
    y+=(b2*c)%m;                // (n-1)!*( n*(n-1)/2 + (n-1)*(n-2)/4 ) mod m
    
    // here y should hold your answer
    }

however be careful older compilers do not have full support of 64 bit integers and can produce wrong results or even does not compile.但是请注意,较旧的编译器不完全支持 64 位整数,可能会产生错误的结果,甚至无法编译。 In such case use big integer lib or compute using 2*32bit variables or look for 32 bit modmul implementation.在这种情况下,使用大 integer 库或使用 2*32 位变量进行计算或寻找 32 位modmul实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM