我受到这是马特·帕克的视频的启发,使用Farey序列将浮点数转换为分数的字符串表示,我做得如何?我有多好地遵循了F#工作流和模式(我对这门语言很陌生)?它是否可以做得更好,或者更确切地说,一个“专业”的F#开发人员如何编写这个函数?提前感谢!
let toFraction num =
let rec farey n0 d0 n1 d1 =
let n2 = n0 + n1
let d2 = d0 + d1
match (n2 / d2) with
| x when abs (x - num) < 1e-5 -> string n2 + " / " + string d2
| x when x < num -> farey n2 d2 n1 d1
| x when x > num -> farey n0 d0 n2 d2
| _ -> "" // Compiler detects "incomplete pattern matches on this expression without this wildcard,
// maybe this is where my method can be improved?
farey 0. 1. 1. 1.
此外,此问题假定输入num
位于集0 <= num < 1
中。
发布于 2020-07-22 01:47:37
关于它本身的函数和算法,没有什么可说的。它是一个普通的递归函数--带有尾调用--对于递归函数来说是最优的。
我发现作为返回值的字符串并不真正有用。相反,我会返回一个由两个整数组成的元组,表示分子和分母。
let toFraction (num: float): (int * int) = etc...
或者,您可以将受歧视的工会定义为:
type Fraction = Fraction of int * int
..。用于:
let toFraction num =
if num <= 0.0 || num >= 1.0 then
failwith "Invalid input"
else
let rec farey n0 d0 n1 d1 =
let n2 = n0 + n1
let d2 = d0 + d1
match float n2 / float d2 with
| x when abs (x - num) < 1e-10 -> Fraction(n2, d2)
| x when x < num -> farey n2 d2 n1 d1
| x when x > num -> farey n0 d0 n2 d2
| _ -> failwith "Something went completely wrong" // just to fulfill the pattern matching - it should never happen
farey 0 1 1 1
并被称为
let (Fraction(num, denom)) = toFraction value
printfn "%d / %d" num denom
如图所示,我选择使用整数而不是浮点数来运行farey
。您应该测试这是否比使用浮点数更有效。
match (n2 / d2) with
你不需要括号。
num
在set0 <= num < 1
中
0 = num
是一个边缘情况,被错误地计算为
1 / 100001
如果希望将0
包含在域中,则需要使用值-1 0 1 1
启动faray
。然后它将返回"0 / 1"
。
即使您在注释中指定,假设num
应该介于0到1之间,您也应该防止无效输入,特别是因为无效输入可能导致无限递归循环。
https://codereview.stackexchange.com/questions/245822
复制相似问题