【问题标题】:Mathematical modulus in c#c#中的数学模数
【发布时间】:2010-04-22 13:10:49
【问题描述】:

c# 中是否有一个库函数用于数字的数学模数 - 我特别指的是负整数模正整数应该产生正结果。

编辑以提供示例:

-5 模 3 应该返回 1

【问题讨论】:

    标签: c# modulo


    【解决方案1】:

    试试(a % b) * Math.Sign(a)

    试试这个;它工作正常。

    static int MathMod(int a, int b) {
        return (Math.Abs(a * b) + a) % b;
    }
    

    【讨论】:

    • +1 是第一个发布正确算法的人(但要注意溢出!)。不过,要严格回答他的问题,不,框架中没有为此内置任何内容。
    • 被接受为第一个正确的算法,但我认为我更可能使用 ((a % b) + b) % b
    • Math.Abs​​ 在这个实现中非常慢,((a % b) + b) % b 在我使用 c# .net 4 的基准测试中是最快的。
    • 此方法溢出警告!!
    • 我唯一要改变的是变量的名称分别为除数和除数,类似于arduino.cc/en/Reference/Modulo
    【解决方案2】:
    x < 0 ? ((x % m) + m) % m : x % m;
    

    【讨论】:

    • 为什么要使用三元运算符?
    • @penguat:因为如果 x 是非负数,那么就没有理由进行额外的工作。
    • 我不确定平均而言哪个工作量更大,条件加法或固定加法和模数,在我的情况下并不重要。无论如何,这个答案是正确的。谢谢。
    • @penguat:很难说;我总是认为除法和模运算相对昂贵(除非它们是微不足道的,例如除以 2 或 mod 2)。我想三元运算符的开销只是检查和跳转的几个周期。另外,在这个计算中,没有非负 x 溢出的机会。但是,如果没有三元运算符,如果 x = 1m = int.MaxValue(或在 0 int.MaxValue 的任何情况下),您可能会溢出。
    • 我肯定猜想额外的模数比现代处理器上的分支更快。但是,我从未测试过它,所以我真的不知道。此外,这是一个非常细微的区别。我不确定哪个更具可读性。一开始我想说没有三元运算符,但是当我想到 x
    【解决方案3】:

    那么定义(如果我没记错的话)是这样的

    a mod b = a - b * floor(a/b)

    它可能很慢并且要小心整数除法,就像内置的模数一样:)

    其他选项是根据操作数的符号修改内置模数的结果。像这样的:

    if(a < 0 && b > 0)
    {
        return (a % b + b) % b;
    }
    else if ....
    

    【讨论】:

      【解决方案4】:
      a < 0 ? ((a+1)%b + b-1) : (a%b);
      

      只需要一个 % 操作 (and one ternary op) 并且不需要乘法

      【讨论】:

        【解决方案5】:

        如果您正在使用这些算法中的任何一种,并且还需要进行除法,请不要忘记确保在适当的时候减去 1。

        即,

        如果-5 % 2 = -1-5 / 2 = -2,如果你关心-5 / 2 * 2 + -5 % 2 = -5,那么当你计算-5 % 2 = 1时,你也计算-5 / 2 = -3

        【讨论】:

        • 我不太清楚你在这里得到了什么......我通常会保留原始数字而不是尝试重建它。
        • 我不是建议你重建它。我只是担心您的算法也可能使用 / 运算符并取决于它们是否一致。
        【解决方案6】:

        修复:

        (ans=a%b)

        【讨论】:

        • -10 mod 3 怎么样?您的解决方案将在所需答案为 2 的情况下给出 -1。
        • @penguat a=-10 , b=3 ans= -1
        【解决方案7】:

        我知道问题不是问的,但我只是编写并测试了一个返回商的方法。我找的时候没找到,所以我想把它放在那里。

        /// <summary>
        /// Compute integer quotient and remainder of <paramref name="dividend"/> / <paramref name="divisor"/>
        /// where the <paramref name="remainder"/> has the same sign as <paramref name="divisor"/>, and is
        /// between zero (inclusive) and the <paramref name="divisor"/> (exclusive). As always,
        /// (quotientResult * <paramref name="divisor"/> + <paramref name="remainder"/> == <paramref name="dividend"/>).
        /// </summary>
        public static int DivRemPeriodic(int dividend, int divisor, out int remainder) {
            var quotient = Math.DivRem(dividend, divisor, out remainder);
            if (divisor > 0 ? remainder < 0 : remainder > 0) {
                remainder += divisor;
                quotient -= 1;
            }
            return quotient;
        }
        

        【讨论】:

        • 这里的余数等同于我要求的模数 - 以及商。对于小于零的除数,这可能会产生不同的结果。
        • 噢!是的,我的意思是“也返回商”。已更正。它适用于负除数,结果如评论文档中所示。余数(又名“模数”)将与除数具有相同的符号。对于负除数,模数在 (-divisor,0] 范围内是周期性的。
        【解决方案8】:

        【讨论】:

        • 不,这在做 -5 % 2 时不会产生积极的结果
        • 他希望 -5 % 2 成为 +1,而不是 -1。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-29
        • 2021-03-05
        • 1970-01-01
        相关资源
        最近更新 更多