4

我正在尝试制作一个可以计算实数的计算分数的程序。它完全可以正常工作,除非我尝试对负实数执行此操作,例如“-71/23”或小数“-3,086 ...”。

如果我计算 +71/23 的连分数,我得到 [3; 11; 2]。这是对的。据我了解,如果我尝试为 -71/23 执行此操作,我应该得到相同的 int 列表,但第一个元素是负数(通过笔和纸工作)。所以应该是 [-3; 11; 2]。但它不工作。我得到 [-3; -11;-1; -1],即每个负数加上一个额外的负数。

我认为我需要创建一个分支,告诉函数只允许 int 列表的第一个数字为负数 - 其余的应该返回正数。我尝试了不同的东西,但我不确定如何解决。

顺便说一句,这是家庭作业。

在此先感谢,斑马板

let rec float2cfrac (x : float) : int list =
    let q = int x
    let r = x - (float q)
    match x with 
    | _ when r < 0.000000001 && r > -0.000000001 -> [q]
    | _ when System.Math.Ceiling(x) - x <0.0001 -> [int (x + 1.0)]
    | _ when q < 0 -> [-q] // this is the line where I want to do it, not sure what to do tho 
    | _ -> q :: float2cfrac (1.0 / r)

printfn "%A" (float2cfrac (-71.0/23.0))

编辑:使用注释移动代码并更改代码格式。

编辑:经过大量工作,我现在找到了解决方案:D 只需添加一个额外的行,说明如果 x 为负,则 -q 而不是 q :) 另请参阅下面我已接受作为答案的评论,您需要更改并添加一些功能:)

  | _ when x < 0.0 -> -q :: float2cfrac (1.0 / r)   
4

3 回答 3

2

我只取绝对值,然后在最后应用符号:

let rec float2cfrac (x : float) : int list =
  let safeX = abs x
  let signX = sign x
  let q = int safeX
  let r = safeX - (float q)
  match x with 
  | _ when r < 0.000000001 && r > -0.000000001 -> [q]
  | _ when System.Math.Ceiling(safeX) - safeX <0.0001 -> [int (safeX + 1.0)]
  | _ -> q :: float2cfrac (1.0 / r)
  |> List.map ( fun rawQ -> rawQ * signX )

来自 fsi:

> float2cfrac (71./23.);;                                                                                                                    
  val it : int list = [3; 11; 2]                                                                                                                                                                                                                  
> float2cfrac (-71./23.);;                                                                                                                    
  val it : int list = [-3; -11; -2]                                                                                                                           
于 2020-10-09T15:50:01.460 回答
0

当然。在任何语言中,您都可以做到这一点。

一旦你知道了正有理的系数,那么只需对其系数进行简单的操作就可以否定它。请记住,为了使其成为合法的 CF,所有拖尾系数(分号后的系数)都应该是正数。

然而,在得出结论之前,让我们先看看什么是负分数。设x为 具有 整数 部分w和 分数 部分的分数f。我们可以这样写;

-x =  w + f where 0 < f < 1
 x = -w - f

然而,分数总是表示为总和,如w + f. 我的意思是当我们写成时,我们的意思是2 + 3/4where wis2fis 3/4。为了将其转换为我们喜欢的否定的正确和符号;

 x = (-w - 1) + (1 - f)

哪个产生的否定是(-2-1)+(1-3/4) = -3 + 1/4正确的?

所以现在一切都很简单。我们已经有了w-3 的部分。所以让我们计算f部分(1/4)的CF系数,它是[0;4]。现在显然我们只需要添加wa0系数的(头部)[-3;4],作为旁注,它也相当于[-3;3,1]但现在不要考虑这个。

这就像上面显示的一样简单,但是它变得更加简单。请记住,我提到了直接操纵输入有理的系数来否定它。为了使答案保持合理的长度,我将绕过证明,但规则是这样的;

x是连分数,[a0; a1, a2, ...an]是它的系数。然后

x = [a0, a1, a2, a3, ...] ⇒ −x = [−a0 − 1, 1, a1 − 1, a2, a3, ...]

所以就是这样。回到你的问题。+71/23 实际上是 3 + 2/23 ,其系数类似于[3; 11, 2]then 根据上述规则,否定会将其系数转换[-3-1; 1, 11-1, 2]为 is[-4;1,10,2][-4;1,10,1,1]。总和符号-4 + 21/23

于 2022-02-21T11:42:45.740 回答
0

上面的代码计算正确,但我认为问题在于函数必须得到这个输出 [-3; 11; 2],所以只有第一个数字会是负数:D 有什么办法吗?解决了

于 2020-10-10T14:15:33.147 回答