F#力问题接受这两个论点可以bigints
-
27-10-2019 - |
题
我目前正在试验F#。该文章,在因特网上找到的都是有用的,但作为一个C#程序员,我有时候会遇到的情况下,我认为我的解决方法会有所帮助,但它并没有或只是部分地帮助。
所以我的知识缺乏的#(和最可能的是,如何编译工作)是可能的原因,我为什么完全大吃一惊的时候。
例如,我写了一C#程序,以确定完善的数字。它使用的已知形式的Euclids证明,一个完美的数量可以形成一个总理梅森2p−1(2p−1)(其中2p-1是总理,以及p被表示为电力)。
由于帮助的F#国'**'可用于计算权力,但使用浮点,我试图建立一个简单的功能与bitshift操作员(<<<)(注意,我编辑这个代码指出需要):
let PowBitShift (y:int32) = 1 <<< y;;
然而,当在运行测试,并寻找改进性能,我也尝试了一种形式,我记得从使用米兰达(a功能的程序语言,也),其中采用递归和一个模式匹配计算的权力。主要好处是,我可以使用的变量 y 作为64位整数,这是不可能的标准bitshift操作员。
let rec Pow (x : int64) (y : int64) =
match y with
| 0L -> 1L
| y -> x * Pow x (y - 1L);;
事实证明,这一功能是实际上更快地,但我无法(尚未)了解原因为何。也许这是一个不知识产权的问题,但我仍然感到好奇。
该秒的问题将是,在计算完美的数字,你碰到的事实,int64无法显示大的数字过境后发现第9perfectnumber(其形成的力量31).我试图找出是否可以使用BigInteger对象(或bigint类型)之后,但在这里我的知识F#是阻止我一个位。是否有可能创建一个powerfunction其接受这两个论点可以bigints?
我现在有这样的:
let rec PowBigInt (x : bigint) (y : bigint) =
match y with
| bigint.Zero -> 1I
| y -> x * Pow x (y - 1I);;
但它抛出一个错误,bigint。零没有定义。所以我在做的事情是错误的。0I是不能接受作为替代,因为它给出了这样的错误:
Non-primitive numeric literal constants cannot be used in pattern matches because they
can be mapped to multiple different types through the use of a NumericLiteral module.
Consider using replacing with a variable, and use 'when <variable> = <constant>' at the
end of the match clause.
但一个模式匹配器无法使用'当'的发言。是否有另一种解决方案做到这一点?
在此先感谢,并请原谅我的长员额。我只想表达我的'挑战'明确的,因为我可以。
解决方案
我不明白为什么你需要的 y
是一个 int64
或 bigint
.根据 这个链接, 最大的称梅森数是一个 p = 43112609
, ,哪里 p
确实是内部范围的 int
.
具有 y
作为一个整数,可以使用的标准操作员 pown : ^T -> int -> ^T
而不是因为:
let Pow (x : int64) y = pown x y
let PowBigInt (x: bigint) y = pown x y
关于你的问题的模式匹配 bigint
, 错误消息表示相当清楚,可以使用模式匹配的通过 when
卫兵:
let rec PowBigInt x y =
match y with
| _ when y = 0I -> 1I
| _ -> x * PowBigInt x (y - 1I)
其他提示
我认为定义PowBigInt
的最简单方法是使用if
而不是模式匹配:
通用标签
问题在于bigint.Zero
是返回值的静态属性,但是模式只能包含(恒定)文字或F#活动模式。它们不能直接包含属性(或其他)调用。但是,如果您仍然喜欢where
,则可以在match
子句中编写其他约束:
通用标签
作为旁注,您可以使用 tail-recursion 使功能更高效(其思想是,如果函数将递归调用作为最后一件事,则可以对其进行更多编译有效): 通用标签
关于PowBitShift
函数-我不确定为什么它要慢一些,但是它绝对不能满足您的需求。仅当基数为2时,才能使用移位实现功率。
您不需要创建Pow函数。 (**)运算符对于bigint-> int-> bigint有重载。 只有第二个参数应该是整数,但是对于您的情况,我认为这不是问题。 尝试
bigint 10 ** 32 ;; 通用标签
另一种选择是内联函数,以便它与所有数字类型(支持必需的运算符:(*)
,(-)
,get_One
和get_Zero
)一起使用。
通用标签
我可能建议像Tomas推荐的那样将其尾部递归。