Reputation: 35
I wanted to get to get the precision of a decimal number for my application, I tried several methods but I couldn't get what i wanted.
At starter i tried to convert the float to a string, and do a simple split on it and stock that in a list of ints, then gets the length of the list
let a = 12.12345678910111213141516;;
let stringA = string_of_float a;;
let list_of_ints stringA = List.map int_of_string (Str.split (Str.regexp "\.") stringA);;
let stringList = list_of_ints stringA;;
let thedecimal = string_of_int (List.nth stringList 1);;
S.length thedecimal;;
the problem is whenever i have more than 10 numbers in the characteristic side of my float it doesn't work, it always return 10
val a : float = 12.1234567891011125
val stringA : string = "12.1234567891"
val list_of_ints : string -> int list = <fun>
val stringList : int list = [12; 1234567891]
val thedecimal : string = "1234567891"
- : int = 10
my second method was trying to do a subtraction between the float number and it's characteristic, so that i get the mantissa, then stock it on a list and get the length of it minus 2 (0 and the .)
let b = int_of_float a;;
let c = a -. (float_of_int b);;
S.length (string_of_float c)-2;;
It returns 12, which is weird cause I'm expecting a 23,
val b : int = 12
val c : float = 0.123456789101112463
- : int = 12
I'm new with Ocaml. If anyone have any solution to how get the precision, I need your help, Thank you.
Upvotes: 3
Views: 2430
Reputation: 991
Due to the limited number of bits in the representation of doubles, the maximal precision is 324. See Wikipedia.
By compromising precision, the subnormal representation allows even smaller values up to about 5 × 10−324.
The following function is what you want.
let precision_of_float f =
let (fractional, _) = modf f in
let fractional_string = (Printf.sprintf "%.324f" fractional) in
(* remove ending zeros *)
let fractional_string = Str.replace_first (Str.regexp "0+$") "" fractional_string in
(* fractional_string is of the form 0.[0-9]* *)
String.length fractional_string - 2
Upvotes: 1
Reputation: 6144
Apparently, string_of_float
decided to limit the number of displayed significant digits to twelve (I'd have to look into it to be sure).
This is actually a good thing, because a double could be represented as a pretty big number.
# let f = 0.123456789012345678901234567890;;
val f : float = 0.123456789012345677
# let s = string_of_float f;;
val s : string = "0.123456789012"
# let s' = Printf.sprintf "%.10f" f;;
val s' : string = "0.1234567890"
# let s'' = Printf.sprintf "%.30f" f;;
val s'' : string = "0.123456789012345677369886232100"
# let s''' = Printf.sprintf "%.60f" f;;
val s''' : string =
"0.123456789012345677369886232099815970286726951599121093750000"
(* longer than this one just add zeroes *)
Now, you're asking for a number actual precision. According to Wikipedia:
- Sign bit: 1 bit
- Exponent: 11 bits
- Significand precision: 53 bits (52 explicitly stored)
And furthermore...
The format is written with the significand having an implicit integer bit of value 1 (except for special data, see the exponent encoding below). With the 52 bits of the fraction significand appearing in the memory format, the total precision is therefore 53 bits (approximately 16 decimal digits, 53 log10(2) ≈ 15.955).
Between 252=4,503,599,627,370,496 and 253=9,007,199,254,740,992 the representable numbers are exactly the integers. For the next range, from 253 to 254, everything is multiplied by 2, so the representable numbers are the even ones, etc. Conversely, for the previous range from 251 to 252, the spacing is 0.5, etc.
The spacing as a fraction of the numbers in the range from 2n to 2n+1 is 2n−52. The maximum relative rounding error when rounding a number to the nearest representable one (the machine epsilon) is therefore 2−53.
So you have it, your precision is around 2^-53
with respect to your float's value. This gives you around 15 or 16 decimal digits of precision for any float.
As a side note, if you're using regexps on a float, you need to calm down and think about kittens for a minute.
Upvotes: 2