0

This function takes a float then spits out the two integers for the decimal value. At least that was the intention

let flr (x:float) = float(int(x))

let f x =
 let r y = let x = x * y in x = flr(x)
 let rec f y =
  if r(y)
   then x*y,y
    else f(y+1.0)
 f 1.0

f 0.2;; val it: float * float = (1.0, 5.0)

f 3.14;; val it: float * float = (157.0, 50.0)

Here is an example where the integers, er will be integers eventually rather, have not been "simplified"

f 0.14;; val it: float * float = (35.0, 250.0)

Checking the fractional part to be less than .01, as opposed to equaling exactly zero, got around this issue but I don't really like that solution. So I set it back to what you see in the code above. I am using the function below for some of the values that do not simplify though:

let g (x,y) =
 let rec f k =
  if x/k = flr(x/k)
   then g(k)
    else f(k-1.0)
 and g k =
  if y/k = flr(y/k)
   then x/k,y/k
    else f(k-1.0)
 if x < y then f x else f y

Anyway, the main issue is this value:

3.142857143

Homeboy just keeps grinding without stack errors and I'm not sure what I've ran into here. Any clarity would be awesome! Thanks y'all.

Iter
  • 361
  • 2
  • 10
  • 1
    You can't compare floating-point numbers for equality, because precision is finite. – Fyodor Soikin Jul 23 '22 at 15:56
  • Is this known as a general rule for when working with the type? I wasn't aware. Thank you. For the moment I'd like to keep the types but...I don't know. – Iter Jul 23 '22 at 16:13
  • 1
    To clarify: it's not specifically about `float` and not even specifically about F#. It's an inherent limitation of how floating-point numbers are represented in computers. – Fyodor Soikin Jul 23 '22 at 20:50
  • 1
    Explanation of floating point precision problem: https://stackoverflow.com/questions/588004/is-floating-point-math-broken/588014#588014 – JL0PD Jul 24 '22 at 02:03
  • I will definitely check this out later. Thank you. – Iter Jul 24 '22 at 02:08

1 Answers1

2

Your algorithm is trying to find a rational number to represent a decimal number (represented as a floating point number).

For any input x, you are looking for a number represented as p/q such that x=p/q and you do this by incrementing q, starting from 1 and checking if you can find an integer p to make this work.

This works fine for numbers that have a nice rational representation like 0.2, but it does not work great for numbers like 3.142857 that do not have a simpler rational representation. For 3.142857, you will just keep iterating until you reach 3142857/1000000 (which is technically correct, but not very helpful).

As mentioned in the comments, there are issues caused by the fact that floating-point numbers cannot be precisely compared, but also, iterating like this for 3.142857143 might just take too long.

You can look up better algorithms for finding a rational number for a given decimal. You could also see if you can accept some margin of error. If you do not need a completely precise solution, you could for example change your r test function to something like:

let r y = 
  let x = x * y
  x < flr(x) + 0.0001 && x > flr(x) + 0.0001

This will not give you exactly the same number, but it will likely find a solution that is good enough.

Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553
  • After reading about how floating-point values are stored in memory I was thinking I'll change the relational expression, as you did here. Thank you Tomas! By the way your book on functional programming was fantastic. Making the shift from object oriented to functional programming took a bit of a shift in thinking. Awesome read. Again, thank you. – Iter Jul 27 '22 at 14:16
  • 1
    @Iter I'm glad this was useful and thanks for the nice words about the book! – Tomas Petricek Jul 27 '22 at 21:00