Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Float.toFixed and friends #142

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 68 additions & 4 deletions packages/melange.js/Js.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1593,9 +1593,45 @@ end = struct
let _NaN = Stdlib.Float.nan
let isNaN float = Stdlib.Float.is_nan float
let isFinite float = Stdlib.Float.is_finite float
let toExponential ?digits:_ _ = notImplemented "Js.Float" "toExponential"
let toFixed ?digits:_ _ = notImplemented "Js.Float" "toFixed"
let toPrecision ?digits:_ _ = notImplemented "Js.Float" "toPrecision"

let remove_leading_zeros s =
(* Remove leading zero in the exponent part *)
let regex = Str.regexp "e\\([+-]\\)0" in
Str.global_replace regex "e\\1" s

let toExponential ?digits n =
let result =
match digits with
| None -> Printf.sprintf "%e" n
| Some d ->
if d < 0 || d > 100 then
invalid_arg
"the digits argument passed to toFixed must be between 0 and 100";

Printf.sprintf "%.*e" d n
in
remove_leading_zeros result

let toFixed ?(digits = 0) n =
if digits < 0 || digits > 100 then
invalid_arg
"the digits argument passed to toFixed must be between 0 and 100";
let factor = 10.0 ** float_of_int digits in
let rounded = Float.round (n *. factor) in
Printf.sprintf "%.*f" digits (rounded /. factor)

let toPrecision ?digits n =
let result =
match digits with
| None -> Printf.sprintf "%g" n
| Some d ->
if d < 0 || d > 100 then
invalid_arg
"the digits argument passed to toPrecision must be between 0 and \
100";
Printf.sprintf "%.*g" d n
in
remove_leading_zeros result

let toString ?radix f =
match radix with
Expand All @@ -1607,7 +1643,35 @@ end = struct
if Stdlib.Float.equal (Stdlib.Float.round f) f then
f |> int_of_float |> string_of_int
else Printf.sprintf "%g" f
| Some _ -> notImplemented "Js.Float" "toString ~radix"
| Some radix ->
let module String = Stdlib.String in
if radix < 2 || radix > 36 then
invalid_arg "radix must be between 2 and 36";

let digits = "0123456789abcdefghijklmnopqrstuvwxyz" in

let rec int_to_radix n =
if n < radix then String.make 1 digits.[n]
else int_to_radix (n / radix) ^ String.make 1 digits.[n mod radix]
in

let rec frac_to_radix frac precision =
if precision = 0 then ""
else
let whole_part = int_of_float (frac *. float_of_int radix) in
String.make 1 digits.[whole_part]
^ frac_to_radix
((frac *. float_of_int radix) -. float_of_int whole_part)
(precision - 1)
in

let int_part = int_of_float f in
let frac_part = abs_float (f -. float_of_int int_part) in
let sign = if f < 0. then "-" else "" in

if frac_part = 0. then sign ^ int_to_radix (abs int_part)
else
sign ^ int_to_radix (abs int_part) ^ "." ^ frac_to_radix frac_part 12

let fromString = Stdlib.float_of_string
end
Expand Down
10 changes: 0 additions & 10 deletions packages/melange.js/Js.mli
Original file line number Diff line number Diff line change
Expand Up @@ -1290,19 +1290,9 @@ module Float : sig
val _NaN : float
val isNaN : float -> bool
val isFinite : float -> bool

val toExponential : ?digits:int -> t -> string
[@@alert
not_implemented "is not implemented in native under server-reason-react.js"]

val toFixed : ?digits:int -> t -> string
[@@alert
not_implemented "is not implemented in native under server-reason-react.js"]

val toPrecision : ?digits:int -> t -> string
[@@alert
not_implemented "is not implemented in native under server-reason-react.js"]

val toString : ?radix:int -> t -> string
val fromString : string -> float
end
Expand Down
48 changes: 47 additions & 1 deletion packages/melange.js/test.ml
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,53 @@ let float_tests =
assert_string (Js.Float.toString 80.0) "80";
assert_string (Js.Float.toString 80.) "80";
assert_string (Js.Float.toString 80.0001) "80.0001";
assert_string (Js.Float.toString 80.00000000001) "80");
assert_string (Js.Float.toString 80.00000000001) "80";
assert_string (Js.Float.toString 123.456) "123.456";
assert_string (Js.Float.toString ~radix:2 10.) "1010";
assert_string (Js.Float.toString ~radix:16 255.) "ff";
assert_string (Js.Float.toString ~radix:8 8.) "10";
assert_string (Js.Float.toString ~radix:16 255.1231) "ff.1f837b4a2338";
(* todo: javascript is actually "1010.0001111010111000010100011110101110000101000111101" *)
assert_string (Js.Float.toString ~radix:2 10.12) "1010.000111101011";
assert_string (Js.Float.toString ~radix:2 0.) "0";
assert_string (Js.Float.toString ~radix:16 0.) "0";
assert_string (Js.Float.toString ~radix:8 0.) "0";
assert_string (Js.Float.toString ~radix:36 12345.) "9ix";
assert_string (Js.Float.toString ~radix:10 1000000.) "1000000";
assert_string (Js.Float.toString ~radix:2 255.) "11111111");
test "toExponential" (fun () ->
assert_string (Js.Float.toExponential ~digits:2 0.005) "5.00e-3";
assert_string (Js.Float.toExponential ~digits:5 12345.6789) "1.23457e+4";
assert_string
(Js.Float.toExponential 12345.6789)
(* todo: javascript is actually "1.23456789e+4" *) "1.234568e+4";
assert_string (Js.Float.toExponential ~digits:1 12345.6789) "1.2e+4";
assert_string (Js.Float.toExponential ~digits:2 0.0001234) "1.23e-4";
assert_string (Js.Float.toExponential ~digits:3 1e-10) "1.000e-10";
assert_string (Js.Float.toExponential ~digits:6 1e+20) "1.000000e+20");
test "toFixed" (fun () ->
assert_string (Js.Float.toFixed ~digits:0 123.456) "123";
assert_string (Js.Float.toFixed ~digits:2 123.456) "123.46";
assert_string (Js.Float.toFixed ~digits:5 123.456) "123.45600";
assert_string (Js.Float.toFixed 123.456) "123";
assert_string (Js.Float.toFixed ~digits:3 0.0001234) "0.000";
assert_string (Js.Float.toFixed ~digits:2 1000000.0) "1000000.00";
assert_string (Js.Float.toFixed ~digits:10 1.23456789) "1.2345678900");
test "toPrecision" (fun () ->
assert_string (Js.Float.toPrecision ~digits:4 12345.6789) "1.235e+4";
assert_string (Js.Float.toPrecision ~digits:2 0.00123) "0.0012";
assert_string (Js.Float.toPrecision ~digits:6 12345.6789) "12345.7";
assert_string (Js.Float.toPrecision ~digits:9 12345.6789) "12345.6789";
assert_string
(Js.Float.toPrecision 12345.6789)
(* todo: javascript is "12345.6789" *) "12345.7";
assert_string
(Js.Float.toPrecision ~digits:10 1.23456789)
(* todo: javascript is "1.234567890" *) "1.23456789";
assert_string
(Js.Float.toPrecision ~digits:2 1000000.0)
(* todo: javascript is "1.0e+6" *) "1e+6";
assert_string (Js.Float.toPrecision ~digits:1 1.23456789) "1");
]

let () =
Expand Down
Loading