Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:19
erlang
2072-Implement-the-new-ceil-1-and-floor-1-guard...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 2072-Implement-the-new-ceil-1-and-floor-1-guard-BIFs.patch of Package erlang
From 986d32a62b20c32338dac4dfd27c141c8f9be0fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org> Date: Mon, 20 Jun 2016 13:25:04 +0200 Subject: [PATCH 1/2] Implement the new ceil/1 and floor/1 guard BIFs Implement as ceil/1 and floor/1 as new guard BIFs (essentially part of Erlang language). They are guard BIFs because trunc/1 is a guard BIF. It would be strange to have trunc/1 as a part of the language, but not ceil/1 and floor/1. --- erts/doc/src/erlang.xml | 27 +++++++++++ erts/emulator/beam/bif.tab | 7 +++ erts/emulator/beam/erl_bif_guard.c | 65 +++++++++++++++++++++++++++ erts/emulator/test/num_bif_SUITE.erl | 84 ++++++++++++++++++++++++++++------- erts/preloaded/ebin/erlang.beam | Bin 105100 -> 105400 bytes erts/preloaded/src/erlang.erl | 19 +++++++- lib/compiler/src/beam_validator.erl | 2 + lib/compiler/src/erl_bifs.erl | 2 + lib/compiler/src/sys_core_fold.erl | 2 + lib/compiler/test/bif_SUITE.erl | 4 +- lib/hipe/cerl/erl_bif_types.erl | 12 +++++ lib/stdlib/src/erl_internal.erl | 4 ++ lib/tools/emacs/erlang.el | 2 + 13 files changed, 209 insertions(+), 21 deletions(-) diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index d0a3a77..18a7a5b 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -693,6 +693,19 @@ Z = erlang:adler32_combine(X,Y,iolist_size(Data2)).</code> </func> <func> + <name name="ceil" arity="1"/> + <fsummary>Returns the smallest integer not less than the argument</fsummary> + <desc> + <p>Returns the smallest integer not less than + <c><anno>Number</anno></c>. + For example:</p> + <pre> +> <input>ceil(5.5).</input> +6</pre> + <p>Allowed in guard tests.</p> + </desc> + </func> + <func> <name name="check_old_code" arity="1"/> <fsummary>Check if a module has old code.</fsummary> <desc> @@ -1417,6 +1430,20 @@ true</pre> </func> <func> + <name name="floor" arity="1"/> + <fsummary>Returns the largest integer not greater than the argument</fsummary> + <desc> + <p>Returns the largest integer not greater than + <c><anno>Number</anno></c>. + For example:</p> + <pre> +> <input>floor(-10.5).</input> +-11</pre> + <p>Allowed in guard tests.</p> + </desc> + </func> + + <func> <name name="fun_info" arity="1"/> <fsummary>Information about a fun.</fsummary> <desc> diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -5449,6 +5449,10 @@ translate_gc_bif(void* gcf) return round_1; } else if (gcf == erts_gc_trunc_1) { return round_1; + } else if (gcf == erts_gc_ceil_1) { + return ceil_1; + } else if (gcf == erts_gc_floor_1) { + return floor_1; } else if (gcf == erts_gc_binary_part_2) { return binary_part_2; } else if (gcf == erts_gc_binary_part_3) { diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -4048,6 +4048,10 @@ gen_guard_bif1(LoaderState* stp, GenOpAr op->a[1].val = (BeamInstr) (void *) erts_gc_round_1; } else if (bf == trunc_1) { op->a[1].val = (BeamInstr) (void *) erts_gc_trunc_1; + } else if (bf == ceil_1) { + op->a[1].val = (BeamInstr) (void *) erts_gc_ceil_1; + } else if (bf == floor_1) { + op->a[1].val = (BeamInstr) (void *) erts_gc_floor_1; } else { op->op = genop_unsupported_guard_bif_3; op->arity = 3; diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab index 7a35c02..67eae35 100644 --- a/erts/emulator/beam/bif.tab +++ b/erts/emulator/beam/bif.tab @@ -653,6 +653,13 @@ bif erlang:has_prepared_code_on_load/1 bif maps:take/2 # +# New in 20.0 +# + +bif erlang:floor/1 +bif erlang:ceil/1 + +# # Obsolete # diff --git a/erts/emulator/beam/erl_bif_guard.c b/erts/emulator/beam/erl_bif_guard.c index b42d2dc..458315f 100644 --- a/erts/emulator/beam/erl_bif_guard.c +++ b/erts/emulator/beam/erl_bif_guard.c @@ -141,6 +141,39 @@ BIF_RETTYPE trunc_1(BIF_ALIST_1) BIF_RET(res); } +BIF_RETTYPE floor_1(BIF_ALIST_1) +{ + Eterm res; + FloatDef f; + + if (is_not_float(BIF_ARG_1)) { + if (is_integer(BIF_ARG_1)) + BIF_RET(BIF_ARG_1); + BIF_ERROR(BIF_P, BADARG); + } + GET_DOUBLE(BIF_ARG_1, f); + res = double_to_integer(BIF_P, floor(f.fd)); + BIF_RET(res); +} + +BIF_RETTYPE ceil_1(BIF_ALIST_1) +{ + Eterm res; + FloatDef f; + + /* check arg */ + if (is_not_float(BIF_ARG_1)) { + if (is_integer(BIF_ARG_1)) + BIF_RET(BIF_ARG_1); + BIF_ERROR(BIF_P, BADARG); + } + /* get the float */ + GET_DOUBLE(BIF_ARG_1, f); + + res = double_to_integer(BIF_P, ceil(f.fd)); + BIF_RET(res); +} + BIF_RETTYPE round_1(BIF_ALIST_1) { Eterm res; @@ -621,6 +654,38 @@ Eterm erts_gc_trunc_1(Process* p, Eterm* reg, Uint live) reg, live); } +Eterm erts_gc_floor_1(Process* p, Eterm* reg, Uint live) +{ + Eterm arg; + FloatDef f; + + arg = reg[live]; + if (is_not_float(arg)) { + if (is_integer(arg)) { + return arg; + } + BIF_ERROR(p, BADARG); + } + GET_DOUBLE(arg, f); + return gc_double_to_integer(p, floor(f.fd), reg, live); +} + +Eterm erts_gc_ceil_1(Process* p, Eterm* reg, Uint live) +{ + Eterm arg; + FloatDef f; + + arg = reg[live]; + if (is_not_float(arg)) { + if (is_integer(arg)) { + return arg; + } + BIF_ERROR(p, BADARG); + } + GET_DOUBLE(arg, f); + return gc_double_to_integer(p, ceil(f.fd), reg, live); +} + static Eterm gc_double_to_integer(Process* p, double x, Eterm* reg, Uint live) { diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -1436,6 +1436,8 @@ Eterm erts_gc_abs_1(Process* p, Eterm* r Eterm erts_gc_float_1(Process* p, Eterm* reg, Uint live); Eterm erts_gc_round_1(Process* p, Eterm* reg, Uint live); Eterm erts_gc_trunc_1(Process* p, Eterm* reg, Uint live); +Eterm erts_gc_ceil_1(Process* p, Eterm* reg, Uint live); +Eterm erts_gc_floor_1(Process* p, Eterm* reg, Uint live); Eterm erts_gc_binary_part_3(Process* p, Eterm* reg, Uint live); Eterm erts_gc_binary_part_2(Process* p, Eterm* reg, Uint live); diff --git a/erts/emulator/test/num_bif_SUITE.erl b/erts/emulator/test/num_bif_SUITE.erl index d1c9648..1a1ab0e 100644 --- a/erts/emulator/test/num_bif_SUITE.erl +++ b/erts/emulator/test/num_bif_SUITE.erl @@ -32,6 +32,8 @@ %% list_to_integer/1 %% round/1 %% trunc/1 +%% floor/1 +%% ceil/1 %% integer_to_binary/1 %% integer_to_binary/2 %% binary_to_integer/1 @@ -41,7 +43,7 @@ t_float_to_string/1, t_integer_to_string/1, t_string_to_integer/1, t_list_to_integer_edge_cases/1, t_string_to_float_safe/1, t_string_to_float_risky/1, - t_round/1, t_trunc/1 + t_round/1, t_trunc_and_friends/1 ]). suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -49,7 +51,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [t_abs, t_float, t_float_to_string, t_integer_to_string, {group, t_string_to_float}, t_string_to_integer, t_round, - t_trunc, t_list_to_integer_edge_cases]. + t_trunc_and_friends, t_list_to_integer_edge_cases]. groups() -> [{t_string_to_float, [], @@ -295,30 +297,78 @@ t_round(Config) when is_list(Config) -> -6209607916799025 = round(id(-6209607916799025.0)), ok. -t_trunc(Config) when is_list(Config) -> - 0 = trunc(id(0.0)), - 5 = trunc(id(5.3333)), - -10 = trunc(id(-10.978987)), +%% Test trunc/1, floor/1, ceil/1, and round/1. +t_trunc_and_friends(_Config) -> + MinusZero = 0.0 / (-1.0), + 0 = trunc_and_friends(MinusZero), + 0 = trunc_and_friends(0.0), + 5 = trunc_and_friends(5.3333), + -10 = trunc_and_friends(-10.978987), - % The largest smallnum, converted to float (OTP-3722): + %% The largest smallnum, converted to float (OTP-3722): X = id((1 bsl 27) - 1), - F = id(X + 0.0), + F = X + 0.0, io:format("X = ~p/~w/~w, F = ~p/~w/~w, trunc(F) = ~p/~w/~w~n", [X, X, binary_to_list(term_to_binary(X)), F, F, binary_to_list(term_to_binary(F)), - trunc(F), trunc(F), binary_to_list(term_to_binary(trunc(F)))]), - X = trunc(F), - X = trunc(F+1)-1, - X = trunc(F-1)+1, - X = -trunc(-F), - X = -trunc(-F-1)-1, - X = -trunc(-F+1)+1, + trunc_and_friends(F), + trunc_and_friends(F), + binary_to_list(term_to_binary(trunc_and_friends(F)))]), + X = trunc_and_friends(F), + X = trunc_and_friends(F+1)-1, + X = trunc_and_friends(F-1)+1, + X = -trunc_and_friends(-F), + X = -trunc_and_friends(-F-1)-1, + X = -trunc_and_friends(-F+1)+1, %% Bignums. - 4294967305 = trunc(id(4294967305.7)), - -4294967305 = trunc(id(-4294967305.7)), + 4294967305 = trunc_and_friends(4294967305.7), + -4294967305 = trunc_and_friends(-4294967305.7), + 18446744073709551616 = trunc_and_friends(float(1 bsl 64)), + -18446744073709551616 = trunc_and_friends(-float(1 bsl 64)), + + %% Random. + t_trunc_and_friends_rand(100), ok. +t_trunc_and_friends_rand(0) -> + ok; +t_trunc_and_friends_rand(N) -> + F0 = rand:uniform() * math:pow(10, 50*rand:normal()), + F = case rand:uniform() of + U when U < 0.5 -> -F0; + _ -> F0 + end, + _ = trunc_and_friends(F), + t_trunc_and_friends_rand(N-1). + +trunc_and_friends(F) -> + Trunc = trunc(F), + Floor = floor(F), + Ceil = ceil(F), + Round = round(F), + + Trunc = trunc(Trunc), + Floor = floor(Floor), + Ceil = ceil(Ceil), + Round = round(Round), + + Trunc = trunc(float(Trunc)), + Floor = floor(float(Floor)), + Ceil = ceil(float(Ceil)), + Round = round(float(Round)), + + true = Floor =< Trunc andalso Trunc =< Ceil, + true = Ceil - Floor =< 1, + true = Round =:= Floor orelse Round =:= Ceil, + + if + F < 0 -> + Trunc = Ceil; + true -> + Trunc = Floor + end, + Trunc. %% Tests integer_to_binary/1. diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 652a954..5bd73fe 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -91,7 +91,8 @@ -export([binary_to_list/3, binary_to_term/1, binary_to_term/2]). -export([bit_size/1, bitsize/1, bitstring_to_list/1]). -export([bump_reductions/1, byte_size/1, call_on_load_function/1]). --export([cancel_timer/1, cancel_timer/2, check_old_code/1, check_process_code/2, +-export([cancel_timer/1, cancel_timer/2, ceil/1, + check_old_code/1, check_process_code/2, check_process_code/3, crc32/1]). -export([crc32/2, crc32_combine/3, date/0, decode_packet/3]). -export([delete_element/2]). @@ -100,7 +101,7 @@ -export([error/1, error/2, exit/1, exit/2, external_size/1]). -export([external_size/2, finish_after_on_load/2, finish_loading/1, float/1]). -export([float_to_binary/1, float_to_binary/2, - float_to_list/1, float_to_list/2]). + float_to_list/1, float_to_list/2, floor/1]). -export([fun_info/2, fun_info_mfa/1, fun_to_list/1, function_exported/3]). -export([garbage_collect/0, garbage_collect/1, garbage_collect/2]). -export([garbage_collect_message_area/0, get/0, get/1, get_keys/0, get_keys/1]). @@ -465,6 +466,13 @@ cancel_timer(_TimerRef) -> cancel_timer(_TimerRef, _Options) -> erlang:nif_error(undefined). +%% ceil/1 +%% Shadowed by erl_bif_types: erlang:ceil/1 +-spec ceil(Number) -> integer() when + Number :: number(). +ceil(_) -> + erlang:nif_error(undef). + %% check_old_code/1 -spec check_old_code(Module) -> boolean() when Module :: module(). @@ -828,6 +836,13 @@ float_to_list(_Float) -> float_to_list(_Float, _Options) -> erlang:nif_error(undefined). +%% floor/1 +%% Shadowed by erl_bif_types: erlang:floor/1 +-spec floor(Number) -> integer() when + Number :: number(). +floor(_) -> + erlang:nif_error(undef). + %% fun_info/2 -spec erlang:fun_info(Fun, Item) -> {Item, Info} when Fun :: function(), diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl index 4c0cb67..fd340bd 100644 --- a/lib/compiler/src/beam_validator.erl +++ b/lib/compiler/src/beam_validator.erl @@ -1506,7 +1506,9 @@ bif_type(abs, [Num], Vst) -> bif_type(float, _, _) -> {float,[]}; bif_type('/', _, _) -> {float,[]}; %% Integer operations. +bif_type(ceil, [_], _) -> {integer,[]}; bif_type('div', [_,_], _) -> {integer,[]}; +bif_type(floor, [_], _) -> {integer,[]}; bif_type('rem', [_,_], _) -> {integer,[]}; bif_type(length, [_], _) -> {integer,[]}; bif_type(size, [_], _) -> {integer,[]}; diff --git a/lib/compiler/src/erl_bifs.erl b/lib/compiler/src/erl_bifs.erl index 6b2d781..7240592 100644 --- a/lib/compiler/src/erl_bifs.erl +++ b/lib/compiler/src/erl_bifs.erl @@ -75,10 +75,12 @@ is_pure(erlang, binary_to_list, 1) -> true; is_pure(erlang, binary_to_list, 3) -> true; is_pure(erlang, bit_size, 1) -> true; is_pure(erlang, byte_size, 1) -> true; +is_pure(erlang, ceil, 1) -> true; is_pure(erlang, element, 2) -> true; is_pure(erlang, float, 1) -> true; is_pure(erlang, float_to_list, 1) -> true; is_pure(erlang, float_to_binary, 1) -> true; +is_pure(erlang, floor, 1) -> true; is_pure(erlang, hash, 2) -> false; is_pure(erlang, hd, 1) -> true; is_pure(erlang, integer_to_binary, 1) -> true; diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl index e0de50f..b806517 100644 --- a/lib/compiler/src/sys_core_fold.erl +++ b/lib/compiler/src/sys_core_fold.erl @@ -2949,7 +2949,9 @@ returns_integer(bit_size, [_]) -> true; returns_integer('bsl', [_,_]) -> true; returns_integer('bsr', [_,_]) -> true; returns_integer(byte_size, [_]) -> true; +returns_integer(ceil, [_]) -> true; returns_integer('div', [_,_]) -> true; +returns_integer(floor, [_]) -> true; returns_integer(length, [_]) -> true; returns_integer('rem', [_,_]) -> true; returns_integer('round', [_]) -> true; diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl index 9453ca6..32d5d39 100644 --- a/lib/hipe/cerl/erl_bif_types.erl +++ b/lib/hipe/cerl/erl_bif_types.erl @@ -560,6 +560,9 @@ type(erlang, byte_size, 1, Xs, Opaques) -> strict(erlang, byte_size, 1, Xs, fun (_) -> t_non_neg_integer() end, Opaques); %% Guard bif, needs to be here. +type(erlang, ceil, 1, Xs, Opaques) -> + strict(erlang, ceil, 1, Xs, fun (_) -> t_integer() end, Opaques); +%% Guard bif, needs to be here. %% Also much more expressive than anything you could write in a spec... type(erlang, element, 2, Xs, Opaques) -> strict(erlang, element, 2, Xs, @@ -588,6 +591,9 @@ type(erlang, element, 2, Xs, Opaques) -> type(erlang, float, 1, Xs, Opaques) -> strict(erlang, float, 1, Xs, fun (_) -> t_float() end, Opaques); %% Guard bif, needs to be here. +type(erlang, floor, 1, Xs, Opaques) -> + strict(erlang, floor, 1, Xs, fun (_) -> t_integer() end, Opaques); +%% Guard bif, needs to be here. type(erlang, hd, 1, Xs, Opaques) -> strict(erlang, hd, 1, Xs, fun ([X]) -> t_cons_hd(X) end, Opaques); type(erlang, info, 1, Xs, _) -> type(erlang, system_info, 1, Xs); % alias @@ -2341,6 +2347,9 @@ arg_types(erlang, bit_size, 1) -> %% Guard bif, needs to be here. arg_types(erlang, byte_size, 1) -> [t_bitstr()]; +%% Guard bif, needs to be here. +arg_types(erlang, ceil, 1) -> + [t_number()]; arg_types(erlang, halt, 0) -> []; arg_types(erlang, halt, 1) -> @@ -2361,6 +2370,9 @@ arg_types(erlang, element, 2) -> arg_types(erlang, float, 1) -> [t_number()]; %% Guard bif, needs to be here. +arg_types(erlang, floor, 1) -> + [t_number()]; +%% Guard bif, needs to be here. arg_types(erlang, hd, 1) -> [t_cons()]; arg_types(erlang, info, 1) -> diff --git a/lib/stdlib/src/erl_internal.erl b/lib/stdlib/src/erl_internal.erl index 5d6aa0e..006e794 100644 --- a/lib/stdlib/src/erl_internal.erl +++ b/lib/stdlib/src/erl_internal.erl @@ -63,6 +63,8 @@ guard_bif(binary_part, 2) -> true; guard_bif(abs, 1) -> true; guard_bif(float, 1) -> true; +guard_bif(ceil, 1) -> true; +guard_bif(floor, 1) -> true; guard_bif(trunc, 1) -> true; guard_bif(round, 1) -> true; guard_bif(length, 1) -> true; @@ -271,6 +273,7 @@ bif(bitsize, 1) -> true; bif(bit_size, 1) -> true; bif(bitstring_to_list, 1) -> true; bif(byte_size, 1) -> true; +bif(ceil, 1) -> true; bif(check_old_code, 1) -> true; bif(check_process_code, 2) -> true; bif(check_process_code, 3) -> true; @@ -291,6 +294,7 @@ bif(float_to_list, 1) -> true; bif(float_to_list, 2) -> true; bif(float_to_binary, 1) -> true; bif(float_to_binary, 2) -> true; +bif(floor, 1) -> true; bif(garbage_collect, 0) -> true; bif(garbage_collect, 1) -> true; bif(garbage_collect, 2) -> true; diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el index 73c6b8d..a0f9512 100644 --- a/lib/tools/emacs/erlang.el +++ b/lib/tools/emacs/erlang.el @@ -743,6 +743,7 @@ resulting regexp is surrounded by \\_< and \\_>." "bitsize" "bitstring_to_list" "byte_size" + "ceil" "check_old_code" "check_process_code" "date" @@ -753,6 +754,7 @@ resulting regexp is surrounded by \\_< and \\_>." "erase" "error" "exit" + "floor" "float" "float_to_binary" "float_to_list" -- 2.10.0
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor