0
votes

Ok I have two functions the first of which looks like so:

let dlth x = float (x.ToString().Length)

which takes a float and returns the number of digits, that part works fine. The second function looks like this:

let droot x = ((x ** (1./(dlth x))) % 1.)

which takes a float and raises it to a power equal to 1.0/(number of digits), then takes the result and does modulus 1.0. Which should be zero for a whole number.

so for droot 36. it takes (36.0 ** (1.0/2.0)) which is 6.0 then 6.0 mod 1.0 equals 0.0;

Now, that works fine right up to where I try the number 81.0. (and all numbers higher than 81 that should work) which returns 1.0 for some reason, throwing off my pattern matching. Can anybody tell me why this is happening?

PostScript: this is part of a Project Euler solution. If you know which problem, please DO NOT post the Project Euler solution. I just need help figuring out why the modulus is returning funny results

3

3 Answers

8
votes

Floating-point arithmetic is fraught with peril in any language. On my box

printfn "%f" (0.9999999999999 % 1.0)        

prints

1.000000

Hopefully that will help steer you in the right direction. If you really want to find out if a float "is an integer", then e.g. subtracting the nearest integer and seeing if the absolute value is less than some epsilon (e.g. 0.00001) is a decent bet.

1
votes

If you're getting float inaccuracies, you could take the performance hit with .NET's decimal data type (which is able to represent all numbers representable in base-10). Other than that use more precision (double) or integer math.

0
votes

I agree with Brian that relying on exact floating point representations is dangerous, but I'm not able to reproduce your issue. For me, droot 81.0 gives the expected result of 0.0. What version of F# are you using? Are you running on .NET or Mono?