2
votes

Why does the exponential operator use float variables in OCaml? Shouldn't it allow int variables too?

# 3**3;;
Error: This expression has type int but an expression was expected of type
         float

Works:

# 3.0**3.0;;
- : float = 27.
3
It couldn't allow int variables even if it wanted to, for the same reason that in the case of addition, an operation that is effectively defined for int and for float, the float version +. does not allow int arguments. This is a trade-off in order to enable type inference. Extensions to the Hindley-Milner typesystem are necessary (and some have been designed) to allow 5.0 + 5.0 and 5 + 5. OCaml's shortest version is pretty acceptable in practice: with a recent version, you can use something like Float.(5.0 + 5.0). - Pascal Cuoq
take a look at this similar question: stackoverflow.com/questions/16950687/… - Benoît Guédas

3 Answers

3
votes

So, the existing answers go into how to get around this, but not into why it is the case. There are two main reasons:

1) OCaml doesn't have operator aliasing. You can't have two operators that do the "same thing", but to different types. This means that only one kind of number, integers or floats (or some other representation) will get to use the standard ** interface.

2) pow(), the exponentiation function has historically been defined on floats (for instance, in Standard C).

Also, for another way to get around the problem, if you're using OCaml Batteries included, there is a pow function defined for integers.

2
votes

You can use int

let int_exp x y = (float_of_int x) ** (float_of_int y) |> int_of_float
0
votes

There's a similar question: Integer exponentiation in OCaml

Here's one possible tail-recursive implementation of integer exponentiation:

let is_even n = 
  n mod 2 = 0

(* https://en.wikipedia.org/wiki/Exponentiation_by_squaring *)
let pow base exponent =
  if exponent < 0 then invalid_arg "exponent can not be negative" else
  let rec aux accumulator base = function
    | 0 -> accumulator
    | 1 -> base * accumulator
    | e when is_even e -> aux accumulator (base * base) (e / 2)
    | e -> aux (base * accumulator) (base * base) ((e - 1) / 2) in
  aux 1 base exponent