defmodule ApaDiv do @moduledoc """ APA : Arbitrary Precision Arithmetic - Division - ApaDiv. """ # only used in division when the loop could be inifinite @scale_default Application.get_env(:apa, :scale_default, -1) @scale_limit if @scale_default == -1, do: 321, else: @scale_default @doc """ Division - internal function - please call Apa.div(left, right) In reference to bcmath I call this function bc_div """ @spec bc_div(String.t(), String.t(), integer(), integer()) :: String.t() def bc_div(left, right, precision, scale) when is_binary(left) and is_binary(right) do {left_int, left_exp} = ApaNumber.from_string(left) {right_int, right_exp} = ApaNumber.from_string(right) # bc_div_apa_number({left_int, left_exp}, {right_int, right_exp}, precision, scale) ApaNumber.to_string( bc_div_apa_number({left_int, left_exp}, {right_int, right_exp}), precision, scale ) end def bc_div(left, right, precision, scale) do raise(ArgumentError, "No string input: left: #{inspect(left)} right: #{inspect(right)} precision: #{inspect(precision)} scale: #{inspect(scale)} ") end @spec bc_div_apa_number({integer(), integer()}, {integer(), integer()}) :: {integer(), integer()} def bc_div_apa_number({_left_int, _left_exp}, {right_int, _right_exp}) when right_int == 0 do # ApaNumber tuple for NaN {0, 1} end def bc_div_apa_number({left_int, left_exp}, {right_int, right_exp}) do bc_div_apa_number( {left_int, left_exp}, {right_int, right_exp}, rem(left_int, right_int), 0 ) end def bc_div_apa_number( {left_int, left_exp}, {right_int, right_exp}, rem, _acc ) when rem == 0 do {div(left_int, right_int), left_exp - right_exp} end def bc_div_apa_number({left_int, left_exp}, {right_int, right_exp}, _rem, acc) when acc == @scale_limit do {div(left_int, right_int), left_exp - right_exp} end def bc_div_apa_number({left_int, left_exp}, {right_int, right_exp}, _rem, acc) do {new_left_int, new_left_exp} = ApaNumber.shift_to({left_int, left_exp}, left_exp - 1) bc_div_apa_number( {new_left_int, new_left_exp}, {right_int, right_exp}, rem(new_left_int, right_int), acc + 1 ) end end