1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
include Float32

type t = Float32.t

let demote_f64 x =
  if Float64.eq x x then Float32.of_float @@ Float64.to_float x
  else
    let nan64bits = Float64.to_bits x in
    let sign_field = Int64.(shift_left (shift_right_logical nan64bits 63) 31) in
    let significand_field =
      Int64.(shift_right_logical (shift_left nan64bits 12) 41)
    in
    let fields = Int64.logor sign_field significand_field in
    let nan32bits = Int32.logor 0x7fc0_0000l (Concrete_i32.wrap_i64 fields) in
    Float32.of_bits nan32bits

let convert_i32_s x = Float32.of_float (Int32.to_float x)

(*
 * Similar to convert_i64_u below, the high half of the i32 range are beyond
 * the range where f32 can represent odd numbers, though we do need to adjust
 * the least significant bit to round correctly.
 *)
let convert_i32_u x =
  Float32.of_float
    Int32.(
      if Int32.ge x zero then to_float x
      else to_float (logor (shift_right_logical x 1) (logand x 1l)) *. 2.0 )

(*
 * Values that are too large would get rounded when represented in f64,
 * but double rounding via i64->f64->f32 can produce inaccurate results.
 * Hence, for large values we shift right but make sure to accumulate the lost
 * bits in the least significant bit, such that rounding still is correct.
 *)
let convert_i64_s (x : int64) =
  Float32.of_float
    Int64.(
      if Int64.lt (abs x) 0x10_0000_0000_0000L then to_float x
      else
        let r = if Int64.eq (logand x 0xfffL) 0L then 0L else 1L in
        to_float (logor (shift_right x 12) r) *. 0x1p12 )

let convert_i64_u x =
  Float32.of_float
    Int64.(
      if Int64.lt_u x 0x10_0000_0000_0000L then to_float x
      else
        let r = if Int64.eq (logand x 0xfffL) 0L then 0L else 1L in
        to_float (logor (shift_right_logical x 12) r) *. 0x1p12 )

let reinterpret_i32 = Float32.of_bits

let of_concrete v = v