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
open Ast
(*
--# Round values
--#
--# Round numbers to a specified number of decimal digits.
--#
--# @name round
--# @param x :: Number | Vector | NDArray Numeric input.
--# @param digits :: Int = 0 Decimal digits.
--# @return :: Number | Vector Computed result (scalar or vectorized).
--# @family math
--# @export
*)
let register env =
let apply_round digits named_args =
match Math_common.get_bool_flag "na_ignore" false named_args with
| Error e -> e
| Ok na_ignore ->
let args = Math_common.positional_args_without [ "digits"; "na_ignore" ] named_args in
let factor = Float.pow 10.0 (float_of_int digits) in
let rf x = Float.round (x *. factor) /. factor in
Math_common.map_numeric_unary ~fname:"round" ~na_ignore rf args
in
Env.add "round"
(make_builtin_named ~name:"round" ~variadic:true 1 (fun named_args _env ->
(* Reject unknown named arguments and enforce that `digits` is an integer. *)
let unknown_named =
List.filter
(fun (n, _) ->
match n with
| None -> false
| Some "digits" -> false
| Some "na_ignore" -> false
| Some _ -> true)
named_args
in
match unknown_named with
| (Some arg_name, _) :: _ ->
Error.type_error
(Printf.sprintf "Function `round` received unknown named argument `%s`." arg_name)
| _ ->
let digits_opt =
List.find_opt (fun (n, _) -> n = Some "digits") named_args
in
(match digits_opt with
| Some (_, VInt n) -> apply_round n named_args
| Some _ ->
Error.type_error
"Function `round` expects the `digits` argument to be an integer."
| None -> apply_round 0 named_args)))
env