Angle difference between two bearings: Difference between revisions

Content added Content deleted
m (used whitespace to line up definitions.)
m (Include Erlang solution)
Line 657: Line 657:
-161.503
-161.503
37.2989</pre>
37.2989</pre>
=={{header|Erlang}}==
The real number calculations are done using integer arithmetic to better handle
rounding errors. Erlang uses extended precision integers so there will be no overflow.
The module is tested by running the test function, which in turn matches expected results
with the result of function call.
<lang 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.
</lang>


=={{header|F#|F sharp}}==
=={{header|F#|F sharp}}==