相关疑难解决方法(0)

是否可以将(x == 0 || x == 1)简化为单个操作?

所以我试图在Fibonacci序列中尽可能紧凑地写出第n个数:

public uint fibn ( uint N ) 
{
   return (N == 0 || N == 1) ? 1 : fibn(N-1) + fibn(N-2);
}
Run Code Online (Sandbox Code Playgroud)

但我想知道我是否可以通过改变来使其更加紧凑和高效

(N == 0 || N == 1)
Run Code Online (Sandbox Code Playgroud)

进入单一比较.是否有一些奇特的位移操作可以做到这一点?

c# algorithm optimization arithmetic-expressions

106
推荐指数
9
解决办法
1万
查看次数

从C#调用F#代码

我正在玩F#和C#,并希望从C#调用F#代码.

我设法让它在Visual Studio中以相反的方式工作,方法是在同一个解决方案中有两个项目,并在F#项目中添加C#代码的引用.这样做之后,我可以调用C#代码,甚至在调试时逐步执行它.

我想要做的是F#代码来自C#而不是来自F#的C#代码.我在C#项目中添加了对F#项目的引用,但它的工作方式与以前不同.我想知道如果不手动完成这是否可行.

c# f# interop

77
推荐指数
3
解决办法
4万
查看次数

为什么递归调用导致StackOverflow处于不同的堆栈深度?

我试图弄清楚C#编译器如何处理尾调用.

(答案:他们不是.但是64位JIT会做TCE(尾部呼叫消除).限制适用.)

所以我使用递归调用编写了一个小测试,它打印了在StackOverflowException杀死进程之前调用它的次数.

class Program
{
    static void Main(string[] args)
    {
        Rec();
    }

    static int sz = 0;
    static Random r = new Random();
    static void Rec()
    {
        sz++;

        //uncomment for faster, more imprecise runs
        //if (sz % 100 == 0)
        {
            //some code to keep this method from being inlined
            var zz = r.Next();  
            Console.Write("{0} Random: {1}\r", sz, zz);
        }

        //uncommenting this stops TCE from happening
        //else
        //{
        //    Console.Write("{0}\r", sz); …
Run Code Online (Sandbox Code Playgroud)

.net c# stack-overflow jit tail-recursion

73
推荐指数
1
解决办法
2890
查看次数

生成尾调用操作码

出于好奇,我试图使用C#生成尾调用操作码.Fibinacci是一个简单的,所以我的c#示例如下所示:

    private static void Main(string[] args)
    {
        Console.WriteLine(Fib(int.MaxValue, 0));
    }

    public static int Fib(int i, int acc)
    {
        if (i == 0)
        {
            return acc;
        }

        return Fib(i - 1, acc + i);
    }
Run Code Online (Sandbox Code Playgroud)

如果我在发布中构建并在没有调试的情况下运行它,我就不会出现堆栈溢出.在没有优化的情况下调试或运行它,我确实得到了堆栈溢出,这意味着尾部调用在发布时具有优化功能(这是我的预期).

这个MSIL看起来像这样:

.method public hidebysig static int32 Fib(int32 i, int32 acc) cil managed
{
    // Method Start RVA 0x205e
    // Code Size 17 (0x11)
    .maxstack 8
    L_0000: ldarg.0 
    L_0001: brtrue.s L_0005
    L_0003: ldarg.1 
    L_0004: ret 
    L_0005: ldarg.0 
    L_0006: ldc.i4.1 
    L_0007: sub 
    L_0008: ldarg.1 
    L_0009: ldarg.0 
    L_000a: …
Run Code Online (Sandbox Code Playgroud)

c# recursion f# cil tail-recursion

39
推荐指数
3
解决办法
7245
查看次数

F#尾递归函数示例

我是F#的新手,正在阅读有关尾递归函数的内容,希望有人可以给我两个不同的函数foo实现 - 一个是尾递归的,另一个不是我可以更好地理解这个原理.

f# tail-recursion

33
推荐指数
4
解决办法
2万
查看次数

C#做尾递归吗?

可能重复:
为什么.net/C#不会消除尾递归?

C#会做尾注吗?

我找不到任何文件告诉我它是否有.

c# tail-recursion

32
推荐指数
2
解决办法
2万
查看次数

技术原因是C#没有发出"尾巴".CIL指令?

可能重复:
为什么.net/C#不会消除尾递归?

请使用以下C#代码:

using System;

namespace TailTest
{
    class MainClass
    {
        public static void Main (string[] args)
        {
            Counter(0);
        }

        static void Counter(int i)
        {
            Console.WriteLine(i);
            if (i < int.MaxValue) Counter(++i);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

C#编译器(无论如何)我会将Counter方法编译成以下CIL:

.method private static hidebysig default void Counter (int32 i) cil managed 
{
.maxstack 8
IL_0000:  ldarg.0 
IL_0001:  call void class [mscorlib]System.Console::WriteLine(int32)
IL_0006:  ldarg.0 
IL_0007:  ldc.i4 2147483647
IL_000c:  bge IL_0019
IL_0011:  ldarg.0 
IL_0012:  ldc.i4.1 
IL_0013:  add 
IL_0014:  call void class TailTest.MainClass::Counter(int32)
IL_0019:  ret 
}
Run Code Online (Sandbox Code Playgroud)

上面代码的问题是它会导致堆栈溢出(在我的硬件上约为i = …

.net c# mono compiler-optimization tail-call-optimization

26
推荐指数
2
解决办法
1305
查看次数

在C#中,在算法中使用递归函数是一个好习惯吗?

在许多使用递归的函数式语言中被认为是一种很好的实践.我认为这很好,因为编译器优化了函数式语言的代码.

但是在创建算法时,在C#中使用递归是一种好习惯吗?就C#而言,是否正确,递归算法将导致您的堆栈增长非常显着(如果调用量非常大)并且这根本不会快,并且可能导致堆栈溢出.或者还有一些优化可以使递归函数高效?

如果您在使用函数语言中的递归和C#的算法之间进行一些比较(速度,内存,可读性),我将不胜感激.

c# algorithm recursion performance functional-programming

17
推荐指数
3
解决办法
9133
查看次数

在这里使用尾递归有什么好处?

我一直在阅读文章,描述如何通过使用尾递归版本来减少快速排序的空间复杂性,但我无法理解这是怎么回事.以下是两个版本:

QUICKSORT(A, p, r)
       q = PARTITION(A, p, r)
       QUICKSORT(A, p, q-1)
       QUICKSORT(A, q+1, r)


TAIL-RECURSIVE-QUICKSORT(A, p, r)
   while p < r
      q = PARTITION(A, p, r)
      TAIL-RECURSIVE-QUICKSORT(A, p, q-1)
      p = q+1
Run Code Online (Sandbox Code Playgroud)

(来源 - http://mypathtothe4.blogspot.com/2013/02/lesson-2-variations-on-quicksort-tail.html)

据我所知,这两个都会导致数组的左半部分和右半部分的递归调用.在这两种情况下,一次只处理一半,因此在任何时候只有一个递归调用将使用堆栈空间.我无法看到尾递归快速排序如何节省空间.

上面的伪代码取自文章 - http://mypathtothe4.blogspot.com/2013/02/lesson-2-variations-on-quicksort-tail.html文章中 提供的解释让我更加困惑 -

Quicksort对给定的子数组进行分区并继续递归两次; 一个在左子阵列上,一个在右侧.这些递归调用中的每一个都需要其自己的堆栈空间流.此空间用于在某种递归级别存储数组的索引变量.如果我们想象这是从执行的开始到结束发生的,我们可以看到堆栈空间在每一层加倍.

那么Tail-Recursive-Quicksort如何修复所有这些呢?

好吧,我们现在只对一个子阵列进行递归,而不是在两个子阵列上递归.这消除了在每个执行层加倍堆栈空间的需要.我们通过使用while循环作为执行相同任务的迭代控件来解决这个问题.我们只需更改同一组变量并对新变量使用单个递归调用,而不是需要堆栈为两个递归调用保存变量集.

在常规快速排序的情况下,我没有看到堆栈空间在每个执行层都是如何加倍的.

注意: - 文章中没有提到编译器优化.

algorithm tail-recursion quicksort

16
推荐指数
2
解决办法
9594
查看次数

我可以强制编译器优化特定方法吗?

是否有一个属性可以告诉编译器必须始终优化方法,即使/o+未设置全局编译器开关?

我问的原因是因为我想要动态创建一个基于现有方法的IL代码的方法; 当代码被优化时,我想要做的操作相当容易,但由于编译器生成了额外的指令,因此在非优化代码中变得非常困难.


编辑:关于非优化的更多细节困扰我...

让我们考虑以下阶乘函数的实现:

static long FactorialRec(int n, long acc)
{
    if (n == 0)
        return acc;
    return FactorialRec(n - 1, acc * n);
}
Run Code Online (Sandbox Code Playgroud)

(注意:我知道有更好的方法来计算阶乘,这只是一个例子)

在启用优化的情况下生成的IL非常简单:

IL_0000:  ldarg.0     
IL_0001:  brtrue.s    IL_0005
IL_0003:  ldarg.1     
IL_0004:  ret         
IL_0005:  ldarg.0     
IL_0006:  ldc.i4.1    
IL_0007:  sub         
IL_0008:  ldarg.1     
IL_0009:  ldarg.0     
IL_000A:  conv.i8     
IL_000B:  mul         
IL_000C:  call        UserQuery.FactorialRec
IL_0011:  ret         
Run Code Online (Sandbox Code Playgroud)

但是未经优化的版本是完全不同的

IL_0000:  nop         
IL_0001:  ldarg.0     
IL_0002:  ldc.i4.0    
IL_0003:  ceq         
IL_0005:  ldc.i4.0    
IL_0006:  ceq         
IL_0008:  stloc.1     
IL_0009:  ldloc.1     
IL_000A:  brtrue.s    IL_0010
IL_000C:  ldarg.1 …
Run Code Online (Sandbox Code Playgroud)

c# compiler-construction optimization il

15
推荐指数
1
解决办法
1144
查看次数