RosettaCodeData/Task/Angle-difference-between-two-bearings/Erlang/angle-difference-between-two-bearings.erl
2023-07-01 13:44:08 -04:00

70 lines
2.4 KiB
Erlang

-module(bearings).
%% API
-export([angle_sub_degrees/2,test/0]).
-define(RealAngleMultiplier,16#10000000000).
-define(DegreesPerTurn,360).
-define(Precision,9).
%%%===================================================================
%%% API
%%%===================================================================
%%--------------------------------------------------------------------
%% @doc
%% @spec
%% @end
%%--------------------------------------------------------------------
%%
angle_sub_degrees(B1,B2) when is_integer(B1), is_integer(B2) ->
angle_sub(B2-B1,?DegreesPerTurn);
angle_sub_degrees(B1,B2) ->
NewB1 = trunc(B1*?RealAngleMultiplier),
NewB2 = trunc(B2*?RealAngleMultiplier),
round(angle_sub(NewB2 - NewB1,
?DegreesPerTurn*?RealAngleMultiplier)
/?RealAngleMultiplier,?Precision).
%%%===================================================================
%%% Internal functions
%%%===================================================================
%% delta normalises the angle difference. Consider a turn from 350 degrees
%% to 20 degrees. Subtraction results in 330 degress. This is equivalent of
%% a turn in the other direction of 30 degrees, thus 330 degrees is equal
%% to -30 degrees.
angle_sub(Value,TurnSize) ->
NormalisedValue = Value rem TurnSize,
minimise_angle(NormalisedValue,TurnSize).
% X rem Turn result in 0..Turn for X > 0 and -Turn..0 for X < 0
% specification requires -Turn/2 < X < Turn/2. This is achieved
% by adding or removing a turn as required.
% bsr 1 divides an integer by 2
minimise_angle(Angle,Turn) when Angle + (Turn bsr 1) < 0 ->
Angle+Turn;
minimise_angle(Angle,Turn) when Angle - (Turn bsr 1) > 0 ->
Angle-Turn;
minimise_angle(Angle,_) ->
Angle.
round(Number,Precision) ->
P = math:pow(10,Precision),
round(Number*P)/P.
test() ->
25 = angle_sub_degrees(20,45),
90 = angle_sub_degrees(-45,45),
175 = angle_sub_degrees(-85,90),
-175 = angle_sub_degrees(-95,90),
170 = angle_sub_degrees(-45,125),
-170 = angle_sub_degrees(-45,145),
-118.1184 = angle_sub_degrees( 29.4803,-88.6381),
-139.583283124=angle_sub_degrees(-70099.742338109,29840.674378767),
-72.343918514=angle_sub_degrees( -165313.66662974,33693.989451746),
-161.50295231=angle_sub_degrees( 1174.8380510598,-154146.66490125),
37.298855589=angle_sub_degrees( 60175.773067955,42213.071923544),
passed.