English 中文(简体)
关于Haskell的问题—— C# 改划
原标题:Questions on a Haskell -> C# conversion

Background:

I was "dragged" into seeing this question: Fibonacci s Closed-form expression in Haskell
when the author initially tagged with many other languages but later focused to a Haskell question. Unfortunately I have no experience whatsoever with Haskell so I couldn t really participate in the question. However one of the answers caught my eye where the answerer turned it into a pure integer math problem. That sounded awesome to me so I had to figure out how it worked and compare this to a recursive Fibonacci implementation to see how accurate it was. I have a feeling that if I just remembered the relevant math involving irrational numbers, I might be able to work everything out myself (but I don t). So the first step for me was to port it to a language I am familiar with. In this case, I am doing C#.

我并非完全处在黑暗之中。 我在另一种实用语言(OCaml)方面有丰富的经验,因此,我对很多语言感到有些熟悉。 从转换开始,一切似乎都是直截了当的,因为它基本上界定了一个新的数字类型,以帮助计算。 然而,我打上了翻译方面的几个路障,在完成翻译方面遇到麻烦。 我会得出完全错误的结果。

Analysis:

这里是我翻译的法典:

data Ext = Ext !Integer !Integer
    deriving (Eq, Show)

instance Num Ext where
    fromInteger a = Ext a 0
    negate (Ext a b) = Ext (-a) (-b)
    (Ext a b) + (Ext c d) = Ext (a+c) (b+d)
    (Ext a b) * (Ext c d) = Ext (a*c + 5*b*d) (a*d + b*c) -- easy to work out on paper
    -- remaining instance methods are not needed

fib n = divide $ twoPhi^n - (2-twoPhi)^n
  where twoPhi = Ext 1 1
        divide (Ext 0 b) = b `div` 2^n -- effectively divides by 2^n * sqrt 5

因此,根据我的研究和我可以推断的(如果我错了任何地方的话,我就错了),第一部分宣布了<代码>。 Ext with a Constructionor that will have two 分类/编码参数(和I guess将继承 Eq Show 类型/模块)。

下面是<代码>的实施。 Ext which "derives” from Num. from Integer exercises a transformation from an Integer. negate is the unary negation and subsequently there s binary addition and multiplicationmente.

最后一个部分是实际执行Fibonacci。

Questions:

回答中,hammar(回答者)提到,通过在上的缺省执行处理权。 但是,这种含义是什么,实际上如何适用于这种类型? 是否有“现场”的含蓄数字,我是没有的。 这是否只是对其中的相应数字适用了权宜之计? 我假定,后者是这样做的,最后是这一C#代码:

public static Ext operator ^(Ext x, int p) // "exponent"
{
    // just apply across both parts of Ext?
    return new Ext(BigInt.Pow(x.a, p), BigInt.Pow(x.b, p));
    //     Ext     (a^p)               (b^p)
}

然而,这与我如何看待为什么需要<代码> > > ><> > > 的问题相矛盾,如果实际发生,就不需要。


Now the meat of the code. I read the first part divide $ twoPhi^n - (2-twoPhi)^n as:

区分以下表述的结果:2Phi^n(2-2Phi)^n。

很简单。 Raise 2Phi to the nth power. 减去其他结果。 在此,我们采取双轨退让行动,但我们只是实施无常的否定。 还是不是? 还是可以暗示双轨削减,因为可以把添加和否定结合起来(我们已经这样做)? 我假定后者。 这使我对否定的不确定性更加容易。


The last part is the actual division: divide (Ext 0 b) = b `div` 2^n. Two concerns here. From what I ve found, there is no division operator, only a `div` function. So I would just have to divide the numbers here. Is this correct? Or is there a division operator but a separate `div` function that does something else special?

我不知道如何解释这条线的开端。 它只是一个简单的模式吗? 换言之,只有在第一个参数是0的情况下才能适用? 如果其与否(第一个是非零)? 或者,当我们不关心第一个参数并无条件地适用这一职能时,我是否应该解释它? 这似乎是最大的障碍,使用这两种解释仍然产生不正确的结果。

我是否在任何地方作出任何错误的假设? 还是所有权利,我刚才错误地执行了C#?

Code:

http://pastebin.com/McTanr7Q“rel=“nofollow noretinger”>full source(包括测试)。

// code removed to keep post size down
// full source still available through link above

Progress:

因此,我想我了解一下迄今的回答和评论。

鉴于我们已实施了倍增行动,因此,才需要做通常做的事情:p倍。 它从未穿过我的想法,即我们应当做的是数学课总是告诉我们做的。 添加和否定的默示减小也是一种明显的手法。

我也在执行过程中发现了一个打字。 我补充说,我应该多加多。

// (Ext a b) * (Ext c d) = Ext (a*c + 5*b*d) (a*d + b*c)
public static Ext operator *(Ext x, Ext y)
{
    return new Ext(x.a * y.a + 5*x.b*y.b, x.a*y.b + x.b*y.a);
    //                 ^ oops!
}

Conclusion:

因此,它已经结束。 我只向基本运营商执行,将其改名为“轨道”。 类似数量。 至今,尽管实际投入很大,但与恢复执行一致。 这里是最后法典。

static readonly Complicated TWO_PHI = new Complicated(1, 1);
static BigInt Fib_x(int n)
{
    var x = Complicated.Pow(TWO_PHI, n) - Complicated.Pow(2 - TWO_PHI, n);
    System.Diagnostics.Debug.Assert(x.Real == 0);
    return x.Bogus / BigInt.Pow(2, n);
}

struct Complicated
{
    private BigInt real;
    private BigInt bogus;

    public Complicated(BigInt real, BigInt bogus)
    {
        this.real = real;
        this.bogus = bogus;
    }
    public BigInt Real { get { return real; } }
    public BigInt Bogus { get { return bogus; } }

    public static Complicated Pow(Complicated value, int exponent)
    {
        if (exponent < 0)
            throw new ArgumentException(
                "only non-negative exponents supported",
                "exponent");

        Complicated result = 1;
        Complicated factor = value;
        for (int mask = exponent; mask != 0; mask >>= 1)
        {
            if ((mask & 0x1) != 0)
                result *= factor;
            factor *= factor;
        }
        return result;
    }

    public static implicit operator Complicated(int real)
    {
        return new Complicated(real, 0);
    }

    public static Complicated operator -(Complicated l, Complicated r)
    {
        var real = l.real - r.real;
        var bogus = l.bogus - r.bogus;
        return new Complicated(real, bogus);
    }

    public static Complicated operator *(Complicated l, Complicated r)
    {
        var real = l.real * r.real + 5 * l.bogus * r.bogus;
        var bogus = l.real * r.bogus + l.bogus * r.real;
        return new Complicated(real, bogus);
    }
}

页: 1

最佳回答

[......],第一部分宣布,有2个分类参数的建筑商的类型为“Ext”(而我方将继承Eq和显示类型/模块)。

rel=“noreferer”> 类型/em>。 你们可以认为,它们与C#的接口类似,只有更大的实力。 <代码>deriving 是可用于自动生成少数标准类型类别实施的产品,包括 EqShow>Ord和其他类型。 这减少了必须写的碎片数量。

The instance Num Ext part provides an explicit implementation of the Num type class. You got most of this part right.

[回答者]提到,在Num的违约执行处理权宜之计。 但是,这种含义是什么,实际上如何适用于这种类型? 是否有“现场”的含蓄数字,我是没有的。 这是否只是对其中的相应数字适用了权宜之计?

这一点在我方面是很不明确的。 。 它通过binaryprentiation落实了积极的整体权力。 这是法典的主要“骗局”。

[...] we re doing binary subtraction but we only implemented unary negation. Or did we not? Or can binary subtraction be implied because it could be made up combinding addition and negation (which we have)?

Correct. The default implementation of binary minus is x - y = x + (negate y).

最后一个部分是实际司:divide (Ext 0 b) = b`div' 2^n。 这里有两个关切。 从我发现的情况来看,没有司级操作员,只有干.。 因此,我不得不在此区分人数。 这是否正确? 或者是否有一个司级操作员,而另一个单独的干 function功能则有些特殊?

There is only a syntactic difference between operators and functions in Haskell. One can treat an operator as a function by writing it parenthesis (+), or treat a function as a binary operator by writing it in `backticks`.

<代码>div为间谍司,属于类别<代码>Integral,因此界定了所有类型的星体,包括。 Int(机械化分类)和Integer(任意分类的分类账)。

我不知道如何解释这条线的开端。 它只是一个简单的模式吗? 换言之,只有在第一个参数为0时,才会适用吗? 如果其与否(第一个是非零)? 或者,当我们不关心第一个参数并无条件地适用这一职能时,我是否应该解释它?

这的确是一种简单的模式,可以得出5英镑的系数。 整体部分与向读者表达我们确实期望它永远是零的零点相匹配,如果守则中的某些ug点造成方案坠毁,则方案就会失败。


A small improvement

Replacing Integer with Rational in the original code, you can write fib n even closer to Binet s formula:

fib n = divSq5 $ phi^n - (1-phi)^n
  where divSq5 (Ext 0 b) = numerator b
        phi = Ext (1/2) (1/2)

在整个计算过程中,各处都进行,而不是最后予以节省。 在计算<代码>fib(10^6)时,中间值减少,速度约为20%。

问题回答

首先,Num,Show, Eq为类型类别,而不是类型或模块。 它们与C#的接口相似,但固定而不是动态解决。

Second, exponentiation is performed via multiplication with the implementation of ^, which is not a member of the Num typeclass, but a separate function.

执行

(^) :: (Num a, Integral b) => a -> b -> a
x0 ^ y0 | y0 < 0    = error "Negative exponent"
        | y0 == 0   = 1
        | otherwise = f x0 y0
    where -- f : x0 ^ y0 = x ^ y
          f x y | even y    = f (x * x) (y `quot` 2)
                | y == 1    = x
                | otherwise = g (x * x) ((y - 1) `quot` 2) x
          -- g : x0 ^ y0 = (x ^ y) * z
          g x y z | even y = g (x * x) (y `quot` 2) z
                  | y == 1 = x * z
                  | otherwise = g (x * x) ((y - 1) `quot` 2) (x * z)

This seems to be the missing part of solution.

You are right about subtraction. It is implemented via addition and negation.

Now, the divide function divides only if a equals to 0. Otherwise we get a pattern match failure, indicating a bug in the program.

<代码>div功能是一种简单的分类,相当于<代码>/适用于C#中的整体类型。 在Haskell也设有一个操作员/,但显示的是实际数量分工。

快速执行C#。 我采用了双倍计算法。

比较这种编号为a+b*Sqrt(5)的类型,使之与采用<代码>a+b*Sqrt(-1)的复杂编号。 添加和减小只是同样的工作。 倍增略有不同,因为此处为1吨,但5级。 司略为复杂,但 should太困难。

接触的定义是,数字本身为零倍。 但这当然是缓慢的。 因此,我们利用以下事实:(a*a)*a(a*a)*(a*a)和使用“平方和多倍算法”重写。 因此,我们只需要<条码>log(n),而不是<条码><<<>>>/代码>多种复制品。

仅仅计算各个组成部分的指数就算不上工作。 这是因为你类型的矩阵是斜线。 相比之下,这一数字与复杂数字的财产比较。 你只能单独计算实际和想象部分的指数。

struct MyNumber
{
    public readonly BigInteger Real;
    public readonly BigInteger Sqrt5;

    public MyNumber(BigInteger real,BigInteger sqrt5)
    {
        Real=real;
        Sqrt5=sqrt5;
    }

    public static MyNumber operator -(MyNumber left,MyNumber right)
    {
        return new MyNumber(left.Real-right.Real, left.Sqrt5-right.Sqrt5);
    }

    public static MyNumber operator*(MyNumber left,MyNumber right)
    {
        BigInteger real=left.Real*right.Real + left.Sqrt5*right.Sqrt5*5;
        BigInteger sqrt5=left.Real*right.Sqrt5 + right.Real*left.Sqrt5;
        return new MyNumber(real,sqrt5);
    }

    public static MyNumber Power(MyNumber b,int exponent)
    {
        if(!(exponent>=0))
            throw new ArgumentException();
        MyNumber result=new MyNumber(1,0);
        MyNumber multiplier=b;
        while(exponent!=0)
        {
            if((exponent&1)==1)//exponent is odd
                result*=multiplier;
            multiplier=multiplier*multiplier;
            exponent/=2;
        }
        return result;
    }

    public override string ToString()
    {
        return Real.ToString()+"+"+Sqrt5.ToString()+"*Sqrt(5)";
    }
}

BigInteger Fibo(int n)
{
    MyNumber num = MyNumber.Power(new MyNumber(1,1),n)-MyNumber.Power(new MyNumber(1,-1),n);
    num.Dump();
    if(num.Real!=0)
      throw new Exception("Asser failed");
    return num.Sqrt5/BigInteger.Pow(2,n);
}

void Main()
{
  MyNumber num=new MyNumber(1,2);
  MyNumber.Power(num,2).Dump();
  Fibo(5).Dump();
}




相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签