From 986d32a62b20c32338dac4dfd27c141c8f9be0fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Mon, 20 Jun 2016 13:25:04 +0200 Subject: 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. --- 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 ++ 7 files changed, 26 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl index 4c0cb6780a..fd340bdabc 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 6b2d781a76..7240592e16 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 e0de50f3ae..b8065176a3 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/compiler/test/bif_SUITE.erl b/lib/compiler/test/bif_SUITE.erl index 6d7231b426..6bde2f1da9 100644 --- a/lib/compiler/test/bif_SUITE.erl +++ b/lib/compiler/test/bif_SUITE.erl @@ -67,9 +67,9 @@ food(Curriculum) -> 0 end, Curriculum]. -%% Test trunc/1, round/1. +%% Test trunc/1, round/1, floor/1, ceil/1. trunc_and_friends(_Config) -> - Bifs = [trunc,round], + Bifs = [trunc,round,floor,ceil], Fs = trunc_and_friends_1(Bifs), Mod = ?FUNCTION_NAME, Calls = [begin diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl index 9453ca6c6f..32d5d39460 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 5d6aa0ebe8..006e7946af 100644 --- a/lib/stdlib/src/erl_internal.erl +++ b/lib/stdlib/src/erl_internal.erl @@ -69,8 +69,10 @@ guard_bif(binary_part, 2) -> true; guard_bif(binary_part, 3) -> true; guard_bif(bit_size, 1) -> true; guard_bif(byte_size, 1) -> true; +guard_bif(ceil, 1) -> true; guard_bif(element, 2) -> true; guard_bif(float, 1) -> true; +guard_bif(floor, 1) -> true; guard_bif(hd, 1) -> true; guard_bif(length, 1) -> true; guard_bif(map_size, 1) -> true; @@ -258,6 +260,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; @@ -278,6 +281,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 73c6b8d768..a0f9512c15 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" -- cgit v1.2.3 From 6d40cfd77f1d2f1e1403e4b41c0b53ae6499ea11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Mon, 27 Jun 2016 12:54:04 +0200 Subject: Add math:floor/1 and math:ceil/1 Add math:floor/1 and math:ceil/1 to avoid unnecessary conversions in floating point expressions. That is, instead of having to write float(floor(X)) as part of a floating point expressions, we can write simply math:floor(X). --- lib/compiler/src/beam_type.erl | 2 + lib/compiler/src/beam_validator.erl | 2 + lib/compiler/src/erl_bifs.erl | 2 + lib/compiler/test/float_SUITE.erl | 5 ++ lib/stdlib/doc/src/math.xml | 2 + lib/stdlib/src/math.erl | 13 +++++- lib/stdlib/test/Makefile | 1 + lib/stdlib/test/math_SUITE.erl | 92 +++++++++++++++++++++++++++++++++++++ 8 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 lib/stdlib/test/math_SUITE.erl (limited to 'lib') diff --git a/lib/compiler/src/beam_type.erl b/lib/compiler/src/beam_type.erl index acaf3ede66..b4776294be 100644 --- a/lib/compiler/src/beam_type.erl +++ b/lib/compiler/src/beam_type.erl @@ -592,6 +592,8 @@ is_math_bif(log10, 1) -> true; is_math_bif(sqrt, 1) -> true; is_math_bif(atan2, 2) -> true; is_math_bif(pow, 2) -> true; +is_math_bif(ceil, 1) -> true; +is_math_bif(floor, 1) -> true; is_math_bif(pi, 0) -> true; is_math_bif(_, _) -> false. diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl index fd340bdabc..61aea57906 100644 --- a/lib/compiler/src/beam_validator.erl +++ b/lib/compiler/src/beam_validator.erl @@ -1642,6 +1642,8 @@ return_type_math(log10, 1) -> {float,[]}; return_type_math(sqrt, 1) -> {float,[]}; return_type_math(atan2, 2) -> {float,[]}; return_type_math(pow, 2) -> {float,[]}; +return_type_math(ceil, 1) -> {float,[]}; +return_type_math(floor, 1) -> {float,[]}; return_type_math(pi, 0) -> {float,[]}; return_type_math(F, A) when is_atom(F), is_integer(A), A >= 0 -> term. diff --git a/lib/compiler/src/erl_bifs.erl b/lib/compiler/src/erl_bifs.erl index 7240592e16..7693daaa56 100644 --- a/lib/compiler/src/erl_bifs.erl +++ b/lib/compiler/src/erl_bifs.erl @@ -131,11 +131,13 @@ is_pure(math, asinh, 1) -> true; is_pure(math, atan, 1) -> true; is_pure(math, atan2, 2) -> true; is_pure(math, atanh, 1) -> true; +is_pure(math, ceil, 1) -> true; is_pure(math, cos, 1) -> true; is_pure(math, cosh, 1) -> true; is_pure(math, erf, 1) -> true; is_pure(math, erfc, 1) -> true; is_pure(math, exp, 1) -> true; +is_pure(math, floor, 1) -> true; is_pure(math, log, 1) -> true; is_pure(math, log2, 1) -> true; is_pure(math, log10, 1) -> true; diff --git a/lib/compiler/test/float_SUITE.erl b/lib/compiler/test/float_SUITE.erl index f6095947ca..0ebc71eb9b 100644 --- a/lib/compiler/test/float_SUITE.erl +++ b/lib/compiler/test/float_SUITE.erl @@ -150,6 +150,11 @@ math_functions(Config) when is_list(Config) -> ?OPTIONAL(0.0, math:erf(id(0))), ?OPTIONAL(1.0, math:erfc(id(0))), + 5.0 = math:floor(5.6), + 6.0 = math:ceil(5.6), + 5.0 = math:floor(id(5.4)), + 6.0 = math:ceil(id(5.4)), + %% Only for coverage (of beam_type.erl). {'EXIT',{undef,_}} = (catch math:fnurfla(0)), {'EXIT',{undef,_}} = (catch math:fnurfla(0, 0)), diff --git a/lib/stdlib/doc/src/math.xml b/lib/stdlib/doc/src/math.xml index 1358ce5cbf..70ca6ae78e 100644 --- a/lib/stdlib/doc/src/math.xml +++ b/lib/stdlib/doc/src/math.xml @@ -57,9 +57,11 @@ + + diff --git a/lib/stdlib/src/math.erl b/lib/stdlib/src/math.erl index 97c965e27a..1db48cd0a2 100644 --- a/lib/stdlib/src/math.erl +++ b/lib/stdlib/src/math.erl @@ -25,7 +25,8 @@ -export([sin/1, cos/1, tan/1, asin/1, acos/1, atan/1, atan2/2, sinh/1, cosh/1, tanh/1, asinh/1, acosh/1, atanh/1, exp/1, log/1, - log2/1, log10/1, pow/2, sqrt/1, erf/1, erfc/1]). + log2/1, log10/1, pow/2, sqrt/1, erf/1, erfc/1, + ceil/1, floor/1]). -spec acos(X) -> float() when X :: number(). @@ -63,6 +64,11 @@ atan2(_, _) -> atanh(_) -> erlang:nif_error(undef). +-spec ceil(X) -> float() when + X :: number(). +ceil(_) -> + erlang:nif_error(undef). + -spec cos(X) -> float() when X :: number(). cos(_) -> @@ -88,6 +94,11 @@ erfc(_) -> exp(_) -> erlang:nif_error(undef). +-spec floor(X) -> float() when + X :: number(). +floor(_) -> + erlang:nif_error(undef). + -spec log(X) -> float() when X :: number(). log(_) -> diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile index 28c35aed55..deac04aa66 100644 --- a/lib/stdlib/test/Makefile +++ b/lib/stdlib/test/Makefile @@ -52,6 +52,7 @@ MODULES= \ io_proto_SUITE \ lists_SUITE \ log_mf_h_SUITE \ + math_SUITE \ ms_transform_SUITE \ proc_lib_SUITE \ qlc_SUITE \ diff --git a/lib/stdlib/test/math_SUITE.erl b/lib/stdlib/test/math_SUITE.erl new file mode 100644 index 0000000000..2b29e44228 --- /dev/null +++ b/lib/stdlib/test/math_SUITE.erl @@ -0,0 +1,92 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2007-2016. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +-module(math_SUITE). + +-include_lib("common_test/include/ct.hrl"). + +%% Test server specific exports +-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, + init_per_group/2,end_per_group/2, + init_per_testcase/2, end_per_testcase/2]). + +%% Test cases +-export([floor_ceil/1]). + + +suite() -> + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,1}}]. + +all() -> + [floor_ceil]. + +groups() -> + []. + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + + +init_per_testcase(_Case, Config) -> + Config. + +end_per_testcase(_Case, _Config) -> + ok. + +floor_ceil(_Config) -> + MinusZero = 0.0/(-1.0), + -43.0 = do_floor_ceil(-42.1), + -43.0 = do_floor_ceil(-42.7), + 0.0 = do_floor_ceil(MinusZero), + 10.0 = do_floor_ceil(10.1), + 10.0 = do_floor_ceil(10.9), + + -533.0 = do_floor_ceil(-533.0), + 453555.0 = do_floor_ceil(453555.0), + + -58.0 = do_floor_ceil(-58), + 777.0 = do_floor_ceil(777), + + ok. + +do_floor_ceil(Val) -> + Floor = math:floor(Val), + Ceil = math:ceil(Val), + + true = is_float(Floor), + true = is_float(Ceil), + + if + Floor =:= Ceil -> + Floor; + true -> + 1.0 = Ceil - Floor, + Floor + end. -- cgit v1.2.3