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(回答者)提到,通过在
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 n
th 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