如何有效地表达这个功能

时间:2016-03-05 08:25:59

标签: c++

int f(int n, int mul) {
    if (abs(n)%mul == 0) return n;
    else return f(n - 1, mul);
}

所以它向下舍入到下一个mul。但显然对n的大值不好。如何安全有效地表达?

5 个答案:

答案 0 :(得分:5)

这相对简单,您只需在调整变量时评估变化的表达式,直到结果满足正确的条件:

while (abs(n) % mul != 0) --n;

注意:

  • 虽然这回答了你的问题,但代码仍然很糟糕,但出于不同的原因:
    • 有圆形数字的功能。而不是重新发明轮子,使用其中一个应该是第一个本能的方法。
    • abs()看起来很无辜,但是如果你在二进制补码系统中给出最小的整数呢?根本没有绝对值可以表示为这样的整数。
    • 同样,递减n可能会下溢,从而导致未定义的行为(以及令人惊讶的结果)。
    • 另外,如果mul不是正面怎么办?代码不以任何方式处理这种情况,而函数签名允许它。
    • 最后但并非最不重要的是,首先编写一个循环是愚蠢的。模运算将为您提供第一个操作数到第二个操作数的下一个倍数的距离!但请确保您了解这对负数如何有效。另外,如果模数在与某些值一起使用时导致未定义的行为,我不会感到惊讶。获得99%的权利很容易,剩下的百分比很棘手。
  • 优化尾端递归的编译器可能生成相同的代码,因此无法保证为您提供任何优势。

答案 1 :(得分:4)

RE

  

如何安全有效地表达[递归函数]?

对于非负nmul,您可以这样做

return n - n%mul;

我将可能的负值调整以及如何处理零mul给读者。

这和你能得到的效率差不多;它是欧几里德会使用的,如果他今天活着并使用C ++而不是 [1] COBOL。

另一种选择是

return mul*(n/mul);

是否比第一种效率更高或更低,取决于。

但是,我认为任何差异都不会太小。

你并不是要求最有效率,而只是“有效率”。这意味着合理的效率。只要有效率,我仍然建议测量

测量需要不需要很大的努力。

在许多情况下,只是观察程序运行得相当好,可以是一个足够好的测量(分辨率和精度非常低,但通常足够好)。

[1] 不确定为什么,但我总是认为欧几里德是一个COBOL家伙。 功能

答案 2 :(得分:0)

如果你担心StackOverflow ......那就不要了!

以下函数基本上是tail recursive函数,像GCC这样的编译器会自动将它转换为迭代函数!

int f(int n, int mul) {
    if (abs(n)%mul == 0) return n;

    return f(n - 1, mul);  //Tail recursion
}

REF:

  1. Tail recursion in C++
  2. http://32leav.es/?p=674
  3. 希望这有帮助!

答案 3 :(得分:0)

如果您的第二个参数是如此,它只会舍入到100。接下来是迭代实现。如果您提供更多详细信息,我可能会再次查看。

     int f(int n, int mul)
     {
         while(n%mul != 0)
         {
           n--;
         };

     return n;
     }

答案 4 :(得分:0)

其他哪些用户建议或多或少地为n的有限案例工作。

一般案例的解决方案在哪里:

if (abs(n) % mul == 0)
    return n;
else if (n >= 0)
    return n - abs(n) % mul;
else
    return mul - abs(n) % mul;

或者首选oneliner

return abs(n) % mul == 0 ? n : n - (n >= 0 ? abs(n) % mul : mul - abs(n) % mul);