Given a string of a (possibly big) integer, I need to convert it to floating-point numbers, in OCaml. The problem is that the conversion is not always exact due to rounding errors. For example, float_of_string "61035156250000000000" would return 61035156249999998976. How can I under-approximate and over-approximate the number to get an interval [a, b] where
a is the largest representable floating-point number such that a <= 61035156250000000000
b is the smallest representable floating-point number such that b >= 61035156250000000000?
You have to get an approximate value, bracket the accurate value (which may not be representable as float) and binary search. Here is a short program I wrote to do this:
let num_of_float x =
let two = Num.num_of_int 2 in
let rec expand x =
let fr, wh = modf x in
Num.add_num (Num.num_of_int (int_of_float wh))
(if fr = 0.0 then Num.num_of_int 0 else
Num.div_num (expand (2.0*.fr)) two) in
let fl, ex = frexp x in
if ex <> 0 then Num.mult_num (expand fl) (Num.power_num two (Num.num_of_int ex))
else
expand x
let bracket str =
let x = Num.num_of_string str in
let rec binsearch a b =
let t = (b-.a)*.0.5 +. a in
if (t = a) || (t = b) then (a,b) else
match Num.compare_num x (num_of_float t) with
| -1 -> binsearch a t
| 0 -> (t,t)
| 1 -> binsearch t b
| _ -> failwith "compare_num" in
let near = Num.float_of_num x in
let delta = 1.0 +. (4.0*.epsilon_float) in
binsearch (near/.delta) (near*.delta)
let () =
let l,r = bracket "61035156250000000000" in
Printf.printf "[%.16g = %s, %.16g = %s]\n"
l (Num.string_of_num (num_of_float l)) r (Num.string_of_num (num_of_float r))
Compile with the Num module to get this output:
[6.103515625e+19 = 61035156249999998976, 6.103515625000001e+19 = 61035156250000007168]
You will need to tweak the delta value and check for NaNs, infinity and conversion errors to get a robust method.
This has to due with the fact that float numbers are stored as A_ * pow(2,B_).
What you need is a BigInt
http://caml.inria.fr/pub/docs/manual-ocaml/libref/Big_int.html
Related
Lets say we have a record which defines students:
type student = {
name : string;
age : int;
grades : (float) list;
}
And safe them in a list like this:
let studentlist = [ {name="alex"; age=7; grades=[1.;2.;3.]} ;
{name="bianca"; age=6; grades=[1.;1.;2.]} ];;
My aim is to compute the grade average of a special student which I choose per age, I select the student with the function search:
let search a lst = List.find( fun {age;_} -> a = age)lst
And compute the average with the help-functions , named sum, length and finally avr :
let rec sum lst =
match lst with
| [] -> 0.0
| h :: t -> h +. sum t
let length lst = float_of_int (List.length lst);;
let avr lst = sum lst /. length lst;;
I don't know how to combine those functions to compute the average properly!
Most of what you've done seems to work. For instance, search works.
utop # search 7 studentlist;;
- : student = {name = "alex"; age = 7; grades = [1.; 2.; 3.]}
If you want to access the grades field of that record, use . for record access.
utop # (search 7 studentlist).grades;;
- : float list = [1.; 2.; 3.]
Now that you have a list of float values, finding the sum or average of them should be easy by passing that value as an argument to the relevant function you've already defined.
Bear in mind that when you use List.find in search, if you search for an age that is not present, you will get a Not_found exception that you will want to handle.
As an aside, note that your avr function iterates over the list twice. Once to compute the sum, and ocne to compute the length.
It is possible to computer the sum, the length, and the average in a single pass. We can use a fold to do this. First off, we can define a basic left fold:
let rec foldl f init lst =
match lst with
| [] -> init
| x::xs -> foldl f (f init x) xs
Consider using this to compute the length of a list:
foldl (fun i _ -> i + 1) 0 [1.; 2.; 3.]
When evaluated:
foldl (fun i _ -> i + 1) 0 [1.; 2.; 3.]
foldl (fun i _ -> i + 1) (0 + 1) [2.; 3.]
foldl (fun i _ -> i + 1) (1 + 1) [3.]
foldl (fun i _ -> i + 1) (2 + 1) []
3
But we can pass a tuple of values to foldl, building up the length, sum, and average as we go.
utop # let (len, sum, avg) = foldl
(fun (len, sum, avg) x ->
let sum = sum +. x in
let len = len + 1 in
let flen = float_of_int len in
(len, sum, sum /. flen))
(0, 0., 0.)
[1.; 2.; 3.];;
val len : int = 3
val sum : float = 6.
val avg : float = 2.
I'm trying to write a recursive function in SML that receives two natural numbers n1,n2 and returns the result of n1 div n2
The datatype natural is defined as follows:
datatype natural = zero | Succ of natural
I want to write it in terms of the new datatype , or in other words, not by converting them to their regular form and converting back the result.
Any ideas how division is done in this definition?
You could start by defining subtraction:
exception Negative
fun sub (a, zero) = a
| sub (zero, b) = raise Negative
| sub (Succ a, Succ b) = sub (a, b)
From here, it should be pretty easy to simply count how many times you can subtract n2 from n1 without going negative. In particular, this equation should help:
n1 div n2 = 1 + (n1 - n2) div n2
I'll leave the rest to you.
Similar to Sam Westrick's definition, "number of times you can subtract n2 from n1 without going negative", you could also do integer division with addition and greater-than using the definition, "number of times you can add n2 to itself before it is greater than n1."
datatype nat = Z | S of nat
fun gt (S x, S y) = gt (x, y)
| gt (S _, Z) = true
| gt (Z, _) = false
fun add (x, Z) = x
| add (x, S y) = add (S x, y)
fun divide (_, Z) = raise Domain
| divide (x, y) = (* ... *)
Addition might seem like a conceptually simpler thing than subtraction. But greater-than is a more expensive operator than determining when a number is negative, since the case is incurred by induction, so Sam's suggestion would be more efficient.
You might test your solution with the following tests:
fun int2nat 0 = Z
| int2nat n = S (int2nat (n-1))
fun nat2int Z = 0
| nat2int (S n) = 1 + nat2int n
fun range (x, y) f = List.tabulate (y - x + 1, fn i => f (i + x))
fun divide_test () =
let fun showFailure (x, y, expected, actual) =
Int.toString x ^ " div " ^ Int.toString y ^ " = " ^
Int.toString expected ^ ", but divide returns " ^
Int.toString actual
in List.mapPartial (Option.map showFailure) (
List.concat (
range (0, 100) (fn x =>
range (1, 100) (fn y =>
let val expected = x div y
val actual = nat2int (divide (int2nat x, int2nat y))
in if expected <> actual
then SOME (x, y, expected, actual)
else NONE
end))))
end
type aexp =
| Const of int
| Var of string
| Power of string * int
| Times of aexp list
| Sum of aexp list
let rec diff : aexp * string -> aexp
= fun (exp, var) ->
match exp with
|Const a -> Const 0
|Var x -> if x = var then Const 1 else Var x
|Power (s, i) ->
if s = var then Times [Const i; Power (s, i - 1)] else Power (s, i)
|Times l ->
begin match l with
|h::t -> Sum ((Times (diff (h, var) :: t)) # (h :: Times (diff (Times t, var))))
end
|Sum l ->
begin match l with
|h::t -> Sum (diff(h, var) :: diff(t, var))
end
This code is expected to work as follows :
diff (Times[Const 2; Var "x"], "x")
then the output must be
Times[Const 2; Const 1]
because if we differentiate 2x, the result is 2
but the error occurs and it says :
File "", line 18, characters 20-25:
Error: This variant expression is expected to have type 'a list
The constructor Times does not belong to type list
Why this error happens? I think there are some spots that are wrong, but I can't find any logical incorrectness.
Some mathematical notes:
The derivative of a variable not x by a variable x is zero, not the original variable.
The same for a power of a variable not x, it is also a constant relative to x.
Why only powers of variables, (a+b)^i is not possible. The more general case is as easy as the special case.
For the derivative of the product consider three factors and include that the first recursive step splits u and v*w
(u*v*w)' = u'*v*w + u*(v'*w+v*w')
In a prefix notation this can be written as
diff(*[u,v,w])=+[*[u',v,w],*[u,+[*[v',w],*[v,w']]]]
which should be reflected in something like
|h::t -> Sum ((Times (diff (h, var) :: t)) # (Times (h :: (diff (Times t, var)))))
As two-element lists, could this also be written as
|h::t -> Sum ( Times (diff (h, var) :: t) , Times (h ,diff (Times t, var)))
Let's look at this expression:
h :: Times (diff (Times t, var))
for simplicity let's substitute diff (Times t, var), with the dtdv, so that we have
h :: Times dtdv
The :: infix constructor requires that an expression to the left of its should have type 'a, while an expression to the right should have a value of type 'a list. An expression to the right is Times dtdv, and constructor Times creates values of type aexp, not values of type list.
Btw, you also have two more errors and two more warnings. These errors are of the same kind, i.e., you're trying to apply a value of type aexp in a place where a list is required, i.e., here:
Times (diff (h, var) :: t)) # (h :: Times (diff (Times t, var))
Let's simplify it again
Times (dhv::t) # rest
The # operator expects lists on both sides, and Times something, as we already discussed, are not a list.
It looks like, that it is hard for you to pass through the big amount of parenthesis and precedence rules. I hate parenthesis. So, I always try to use let ... in sparingly, e.g., let's rewrite the following expression:
Sum ((Times (diff (h, var) :: t)) # (h :: Times (diff (Times t, var))))
With a more verbose, but understanble version:
let h' = diff (h,var) in
let t' = diff (Times t,var) in
let lhs = Times (h'::t) in
let rhs = h :: Times t' in
Sum (lhs#rhs)
Now it is much more readable, and you can tackle with all problems one by one.
Also, I'm would suggest not to try to solve everything in a big fat function, but instead separate things into smaller functions that are easier to handle, this will also solve you a problem with the match inside a match, e.g., the following function has a structure that is much easier to understand:
let rec diff : aexp * string -> aexp = fun (exp, var) ->
match exp with
|Const a -> Const 0
|Var x -> if x = var then Const 1 else Var x
|Power (s, i) -> diff_power s i
|Times l -> diff_times l
|Sum l -> diff_sum l
and diff_power s i =
if s = var then Times [Const i; Power (s, i - 1)] else Power (s, i)
and diff_times l = match l with
|h::t -> Sum ((Times (diff (h, var) :: t)) # (h :: Times (diff (Times t, var))))
and diff_sum l = match l with
|h::t -> Sum (diff(h, var) :: diff(t, var))
I am puzzled with my code:
let sum l = match l with
| [] -> 0.0
| h::t -> h +. (sum t);;
It should give me the sum of the numbers in the list. However when I check the code, I found the second code crashes when I use a list of length greater than or equal to 7. Here is the code:
# sum [0.;1.;2.;3.;4.;5.;]
- : float = 15.
# sum [0.;1.;2.;3.;4.;5.;6.]
- : float = 21.
# sum [0.;1.;2.;3.;4.;5.;6.;7.]
- : float = 21.
I am really confused because a modification of it, which operates on int, turned out to be normal:
let rec sumf l = match l with
| []-> 0.0
| h::t-> (float_of_int h) +. sumf t;;
and I do not know what is the essential difference between the two aside from I cast int into float in the second code.
let sum l=
match l with
[]->0.0
|h::t-> h+. (sum t);;
Since you didn't use the rec keyword here, the call to sum in the last line is a call to a sum function that you defined beforehand. Apparently that sum function was buggy.
I don't understand why your code crashes. When I try your sum function with rec keyword, I don't have any problem, otherwise you can't call recursively the sum function.
let rec sum l =
match l with
[] -> 0.
| h :: t -> h +. (sum t);;
You can also use the fold_left function in module List:
let sum l = List.fold_left (+.) 0. l;;
How can I convert float to float option. Here is the function:
let variance (list_ : float list) : float option =
if List.length list_ < 2 then None
else begin
let average tmp_list = List.fold_left(+.) 0. tmp_list /. float(List.length tmp_list) in
let square value = value *. value in
let rec sum tmp_list =
match tmp_list with
| [] -> 0.0
| head::tail -> square (head -. average tmp_list) +. sum tail
in Some (sum list_ /. float(List.length list_))
end
I need sum list_ /. float(List.length list_) to return float option instead of float and I don't know how to do it. I thought if I return float in a float option function it would automatically return float option but I get the following error:
Error: This expression has type float but an expression was expected
of type float option
I have tried wrapping it around Some and failed. Can't seem to find anything on the internet.
EDIT: Added the full code
Your code runs, it just gives the wrong answer. That's because you sum function is incorrect : you should always use the average of the whole list, whereas you use the average from the current element onwards.
let variance l =
let sum l = List.fold_left (+.) 0. l in
let average l =
match List.length l with
0 -> None
| n -> Some (sum l /. float_of_int n) in
match average l with
None -> None
| Some m -> average (List.map (fun x -> (x -. m)**2.) l)