3

I'm trying to make a program that can calculate the calculated fraction of a real number. It works completely fine except when I'm trying to do it for a negative real number, ex "-71/23" or in decimals "-3,086...".

If I calculate the continued fraction of +71/23, I get [3; 11; 2]. This is correct. As far as I've understood, If I then try to do it for -71/23, I should get the same int list, but with the first element being negative (works by pen & paper). So that should be [-3; 11; 2]. But its not working out. I'm getting [-3; -11; -1; -1], which is every number negative plus one extra negative number.

I think that I need to make a branch where I tell the function that only the first number of the int list is allowed to be negative - the rest should be returned positive. I've tried different stuff, but I'm not sure how to work it out.

This is homework by the way.

Thanks in advance, Zebraboard

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))

Edit: Moved code with comment and changed format of the code.

Edit: I have now found the solution after lots of work :D simply add an extra line that says that if x is negative then -q instead of q :) Also see the comment below that I have accepted as an answer, you need to change and add some functions :)

  | _ when x < 0.0 -> -q :: float2cfrac (1.0 / r)   
Zebraboard
  • 210
  • 1
  • 13
  • 1
    Could you fix the formatting of your code sample? This is F# so indentation is significant. Also, the third case of your match statement is a catch-all, so the fourth case will never be evaluated. – Guran Oct 09 '20 at 08:11
  • 1
    Thanks a lot for the input. I think I've fixed the code sample now and moved the code above the fourth statement. – Zebraboard Oct 09 '20 at 08:52
  • 1
    Still not fixed tho. I think it might have something to do with System.Math.Ceiling(x). It will round up if its a positive number, but if its a negativt, it simply just removes the decimals (ex: 3,5 will be 4, -3,5 will be 3). I might have to make it to act different when q is negative or alike, not sure tho – Zebraboard Oct 09 '20 at 09:22

3 Answers3

2

I would just take the absolute value, then apply the sign at the end:

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 )

From fsi:

> float2cfrac (71./23.);;                                                                                                                    
  val it : int list = [3; 11; 2]                                                                                                                                                                                                                  
> float2cfrac (-71./23.);;                                                                                                                    
  val it : int list = [-3; -11; -2]                                                                                                                           
David Kaftan
  • 1,974
  • 1
  • 12
  • 18
  • 1
    Thanks a lot for this input! This is really helpful and is helping me getting on the right track. However, as far as I've understood, it is only possible for the first number to be negative. This is because if you calculate -71/23's continued fraction by hand, you will get [-3; 11; 2]. Therefore, [-3; -11; -2] is not correct I think. – Zebraboard Oct 10 '20 at 15:15
  • 1
    So I think that in order for this to be fully succeded, I need to make the program only allow the first element in the output int list to be negative or alike – Zebraboard Oct 10 '20 at 15:19
  • 2
    I have accepted this answer as you helped me on the way to find the solution. The final solution has been added on the post. Thank you very much, I appreciate it! – Zebraboard Oct 10 '20 at 20:37
  • 1
    Glad I was able to help, and sorry I misunderstood how continued fractions should work. – David Kaftan Oct 12 '20 at 15:51
  • 1
    In CF terminology you are not allowed to use negative integers on the tail (integers following the initial one). The correct answer is `[-4;1,10,2]`. – Redu Mar 29 '22 at 16:44
1

Of course. In any language you can do that.

Once you know the coefficients of the positive rational then just a simple manipulation on it's coefficients would negate it. Keep in mind that in order to make it a legal CF all tailing coefficients (the ones after semicolon) should be positive.

However before jumping into the conclusion lets first see what is a negative fraction. Let x be a fraction with integral part w and fraction part f. We can write it like;

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

However fractions are always expressed as a sum like w + f. I mean when we write like we mean 2 + 3/4 where w is 2 and f is 3/4. In order to convert it to negated proper sum notation we do like;

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

which yields the negation of to be (-2-1)+(1-3/4) = -3 + 1/4 right?

So now everything is straightforward. We already have the w part as -3. So lets calculate CF coefficients of the f part (1/4) and it is [0;4]. Now obviously we just need to add w to the a0 (the head) of the coefficients yielding [-3;4] which, as a side note, is also equivalent to [-3;3,1] but don't think about this now.

This is as simple as shown above however it gets even simpler. Remember i mentioned a direct manipulation of the input rational's coefficients to negate it. To keep the answer in reasonable length i will bypass the proof but the rule is like;

x is a continued fraction and [a0; a1, a2, ...an] are it's coefficients. Then

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

So this is it. Coming back to your question. +71/23 is in fact 3 + 2/23 with coefficients like [3; 11, 2] then according to the above rule a negation would turn it's coefficients into [-3-1; 1, 11-1, 2] which is [-4;1,10,2] or [-4;1,10,1,1]. In sum notation -4 + 21/23.

Note: In the above negation formula, if the a1 - 1 term turns out to be 0 (if a1 = 1) then you can eliminate it (0) and add the previous value (1) with the next value (a2) and merge them. In general any continued fraction in the form of [a0, a1, 0, a3,..., an] should be written like [a0,a1+a3,a4,...,an].

Redu
  • 25,060
  • 6
  • 56
  • 76
-1

The code above is calculating correctly, but I think the problem is that the function has to get this output [-3; 11; 2], so only the first number will be negative :D Is there any way to do it? solved

AlphaList
  • 237
  • 1
  • 12
  • This is obviously wrong because it yiels to `-3 + (1/(11 + (1/2)))` which is `-67/23`. *Is there any way to do it?* Yes.. please see my answer. – Redu Feb 21 '22 at 12:07