diff options
author | Serge Aleynikov <[email protected]> | 2013-01-21 15:36:43 +0100 |
---|---|---|
committer | Björn-Egil Dahlberg <[email protected]> | 2013-01-21 15:36:43 +0100 |
commit | ab27e8699ef2a2bafe574158200993f184de3dc2 (patch) | |
tree | a4365e182109d25ce049244b220844705b7d2a25 /erts/emulator/beam | |
parent | 9f461fbaf0be7aba7c0b8b89be1f0b6f1141b7a5 (diff) | |
download | otp-ab27e8699ef2a2bafe574158200993f184de3dc2.tar.gz otp-ab27e8699ef2a2bafe574158200993f184de3dc2.tar.bz2 otp-ab27e8699ef2a2bafe574158200993f184de3dc2.zip |
Text representation of a float formatted using given options.
This BIF solves a problem of float_to_list/1 that doesn't allow
specifying the number of digits after the decimal point when
formatting floats.
float_to_list(Float, Options) -> string()
Float = float()
Options = [Option]
Option = {decimals, Decimals::0..249} |
{scientific, Decimals::0..249} |
compact
Returns a string which corresponds to the text representation of
a `Float` formatted using given options.
When decimals option is specified the returned value will contain
at most `Decimals` number of digits past the decimal point.
When `compact` option is provided the trailing zeros at the end
of the list are truncated (this option is only meaningful together
with the `decimals` option). When `scientific` option is provided,
the float will be formatted using scientific notation with
`Decimals` digits of precision. If `Options` is `[]` the function
behaves like `float_to_list/1`. When using `decimals` option and
the number doesn't fit in the static internal buffer of 256 bytes
the function throws `badarg`.
Diffstat (limited to 'erts/emulator/beam')
-rw-r--r-- | erts/emulator/beam/atom.names | 3 | ||||
-rw-r--r-- | erts/emulator/beam/bif.c | 68 | ||||
-rw-r--r-- | erts/emulator/beam/bif.tab | 1 | ||||
-rw-r--r-- | erts/emulator/beam/sys.h | 3 |
4 files changed, 74 insertions, 1 deletions
diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names index c47a608215..b74e2785e5 100644 --- a/erts/emulator/beam/atom.names +++ b/erts/emulator/beam/atom.names @@ -144,6 +144,7 @@ atom close atom closed atom code atom command +atom compact atom compat_rel atom compile atom compressed @@ -165,6 +166,7 @@ atom current_location atom current_stacktrace atom data atom debug_flags +atom decimals atom delay_trap atom dexit atom depth @@ -480,6 +482,7 @@ atom scheduler atom scheduler_id atom schedulers_online atom scheme +atom scientific atom scope atom sensitive atom sequential_tracer diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index 97c8114437..182129cd36 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -2917,7 +2917,73 @@ BIF_RETTYPE float_to_list_1(BIF_ALIST_1) need = i*2; hp = HAlloc(BIF_P, need); BIF_RET(buf_to_intlist(&hp, fbuf, i, NIL)); - } +} + +BIF_RETTYPE float_to_list_2(BIF_ALIST_2) +{ + const static int arity_two = make_arityval(2); + int decimals = SYS_DEFAULT_FLOAT_DECIMALS; + int compact = 0; + enum fmt_type_ { + FMT_LEGACY, + FMT_FIXED, + FMT_SCIENTIFIC + } fmt_type = FMT_LEGACY; + Eterm list = BIF_ARG_2; + Eterm arg; + int i; + Uint need; + Eterm* hp; + FloatDef f; + char fbuf[256]; + + /* check the arguments */ + if (is_not_float(BIF_ARG_1)) + goto badarg; + + for(; is_list(list); list = CDR(list_val(list))) { + arg = CAR(list_val(list)); + if (arg == am_compact) { + compact = 1; + continue; + } else if (is_tuple(arg)) { + Eterm* tp = tuple_val(arg); + if (*tp == arity_two && is_small(tp[2])) { + decimals = signed_val(tp[2]); + if (decimals > 0 && decimals < sizeof(fbuf) - 6 /* "X." ++ "e+YY" */) + switch (tp[1]) { + case am_decimals: + fmt_type = FMT_FIXED; + continue; + case am_scientific: + fmt_type = FMT_SCIENTIFIC; + continue; + } + } + } + goto badarg; + } + if (is_not_nil(list)) { + goto badarg; + } + + GET_DOUBLE(BIF_ARG_1, f); + + if (fmt_type == FMT_FIXED) { + if ((i = sys_double_to_chars_fast(f.fd, fbuf, sizeof(fbuf), + decimals, compact)) <= 0) + goto badarg; + } else { + if ((i = sys_double_to_chars_ext(f.fd, fbuf, sizeof(fbuf), decimals)) <= 0) + goto badarg; + } + + need = i*2; + hp = HAlloc(BIF_P, need); + BIF_RET(buf_to_intlist(&hp, fbuf, i, NIL)); +badarg: + BIF_ERROR(BIF_P, BADARG); +} /**********************************************************************/ diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab index 59a91cd40c..a79feb6da3 100644 --- a/erts/emulator/beam/bif.tab +++ b/erts/emulator/beam/bif.tab @@ -64,6 +64,7 @@ bif erlang:external_size/1 bif erlang:external_size/2 ubif erlang:float/1 bif erlang:float_to_list/1 +bif erlang:float_to_list/2 bif erlang:fun_info/2 bif erlang:garbage_collect/0 bif erlang:garbage_collect/1 diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h index 898a30b010..cecaff54a4 100644 --- a/erts/emulator/beam/sys.h +++ b/erts/emulator/beam/sys.h @@ -729,9 +729,12 @@ char * getenv_string(GETENV_STATE *); void fini_getenv_state(GETENV_STATE *); /* xxxP */ +#define SYS_DEFAULT_FLOAT_DECIMALS 20 void init_sys_float(void); int sys_chars_to_double(char*, double*); int sys_double_to_chars(double, char*, size_t); +int sys_double_to_chars_ext(double, char*, size_t, size_t); +int sys_double_to_chars_fast(double, char*, int, int, int); void sys_get_pid(char *, size_t); /* erts_sys_putenv() returns, 0 on success and a value != 0 on failure. */ |