2

I have a string matching the following regex \-?[0-9]*\.[0-9]+ which supposedly represents a IEEE floating point number. It could be single or double precision and I know the type in advance. I need to check if it could be interpreted as a valid value in given precission. Something like:

val is_valid_float: string -> bool
val is_valid_double: string -> bool

For double precision numbers, I can just parse it using float_of_string and catch the exception. I am unsure how to deal with single precision.

krokodil
  • 1,326
  • 10
  • 18
  • I wonder if you could mess around with `Int32.bits_of_float`? Going to check. – Jonathan Chan Jul 27 '17 at 23:04
  • Some preliminary testing suggests `Int32.float_of_bits (Int32.bits_of_float float))` will give `infinity` if the `float` is out of range. Checking the OCaml source. – Jonathan Chan Jul 27 '17 at 23:06
  • The OCaml source just relies on C's conversion from doubles to floats (see `caml_int32_bits_of_float_unboxed` in `byterun/ints.c`. The C spec just says to use the IEEE spec's conversion, but that process seems to be complicated (see https://stackoverflow.com/a/16737725/252042). One might assume that `Int32.float_of_bits (Int32.bits_of_float float))` should indeed be the identity iff `float` is representable as a single-precision float, but I am not an expert, and assuming seems like it might be dangerous, depending on how sure you need to be about this! – Jonathan Chan Jul 27 '17 at 23:20

1 Answers1

0

@JonathanChan's comments are enlightening, probably more so than anything I might say.

However, I'm not even sure what you mean by validation.

Is "1.0000000000000001" a valid float?

 val f : string = "1.0000000000000001"
 # float_of_string f;;
 - : float = 1.
 #

There's no exception to indicate that this number can't be represented as distinct from 1.0.

If you ignore issues of precision, it might not be difficult to test against the representable range just as a string operation.

As @JonathanChan points out, the best answer probably depends on how sure you need to be (and what you want to be sure of, exactly).

Jeffrey Scofield
  • 65,646
  • 2
  • 72
  • 108
  • The representable range goes from -∞ to +∞, since these values are available in both single- and double-precision. One might want to check that the value from the string can be represented precisely (to 24/53 significant bits) instead of by `+inf` or `-inf`. This is is done by checking whether the result of the conversion is infinite. – Pascal Cuoq Jul 28 '17 at 09:38
  • Nice. So then there are no exceptions to be caught for lexically valid strings, it would seem. – Jeffrey Scofield Jul 28 '17 at 11:35
  • However, it seems you need another method for single-precision float, since it has no representation in OCaml. – Jeffrey Scofield Jul 28 '17 at 11:42
  • 2
    My approach is to represent single-precision numbers as OCaml `float`. Most single-precision operations can be emulated exactly with the OCaml operation followed by immediate rounding to single-precision, with this function: https://github.com/TrustInSoft/tis-interpreter/blob/788c24ea1c5f4afe6af6c9de085e4b4d68c3defc/src/libraries/utils/c_bindings.c#L150 . But not parsing from decimal: this needs to be re-implemented, for instance as in https://github.com/TrustInSoft/tis-interpreter/blob/788c24ea1c5f4afe6af6c9de085e4b4d68c3defc/src/libraries/utils/floating_point.ml#L146 – Pascal Cuoq Jul 28 '17 at 14:15
  • I am trying to replicate the behavior of C compiler and I would like to accept constants that it would find correct. In question above I've narrowed it down to specific regexp so we do not need to deal with infinity here. – krokodil Jul 29 '17 at 18:51
  • I just checked and gcc in c99 accepts "1." followed by very many zeros and then "1" as valid floating point literal. – krokodil Jul 29 '17 at 18:54