-module(bigdecimal). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([unscaled_value/1, scale/1, zero/0, one/0, absolute_value/1, signum/1, precision/1, ulp/1, negate/1, truncate_to_bigint/1, rescale/3, add/2, sum/1, subtract/2, compare/2, clamp/3, multiply/2, product/1, trim_zeros/1, divide/3, power/2, from_string/1, from_float/1]). -export_type([big_decimal/0]). -opaque big_decimal() :: {big_decimal, bigi:big_int(), integer()}. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 21). -spec unscaled_value(big_decimal()) -> bigi:big_int(). unscaled_value(Value) -> {big_decimal, Unscaled_value, _} = Value, Unscaled_value. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 26). -spec scale(big_decimal()) -> integer(). scale(Value) -> {big_decimal, _, Scale} = Value, Scale. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 31). -spec zero() -> big_decimal(). zero() -> {big_decimal, bigi_ffi:from(0), 0}. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 35). -spec one() -> big_decimal(). one() -> {big_decimal, bigi_ffi:from(1), 0}. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 53). -spec absolute_value(big_decimal()) -> big_decimal(). absolute_value(Value) -> {big_decimal, erlang:abs(unscaled_value(Value)), scale(Value)}. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 60). -spec signum(big_decimal()) -> integer(). signum(Value) -> _pipe = unscaled_value(Value), _pipe@1 = bigi_ffi:compare(_pipe, bigi_ffi:zero()), gleam@order:to_int(_pipe@1). -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 41). -spec precision(big_decimal()) -> integer(). precision(Value) -> String_length = begin _pipe = unscaled_value(Value), _pipe@1 = erlang:integer_to_binary(_pipe), erlang:byte_size(_pipe@1) end, case signum(Value) of -1 -> String_length - 1; _ -> String_length end. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 68). -spec ulp(big_decimal()) -> big_decimal(). ulp(Value) -> {big_decimal, bigi_ffi:from(1), scale(Value)}. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 72). -spec negate(big_decimal()) -> big_decimal(). negate(Value) -> {big_decimal, bigi_ffi:negate(unscaled_value(Value)), scale(Value)}. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 210). -spec is_even(bigi:big_int()) -> boolean(). is_even(Value) -> case begin _pipe = bigi_ffi:modulo(Value, bigi_ffi:from(2)), bigi_ffi:to(_pipe) end of {ok, 0} -> true; _ -> false end. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 220). -spec get_magnitude(bigi:big_int(), integer()) -> integer(). get_magnitude(Value, Magnitude) -> Quotient = bigi_ffi:divide(Value, bigi_ffi:from(10)), case bigi_ffi:compare(Quotient, bigi_ffi:zero()) of lt -> get_magnitude(Quotient, Magnitude + 1); gt -> get_magnitude(Quotient, Magnitude + 1); eq -> Magnitude end. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 274). -spec multiply_power_of_ten(bigi:big_int(), integer()) -> bigi:big_int(). multiply_power_of_ten(Value, N) -> _assert_subject = N >= 0, true = case _assert_subject of true -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail, module => <<"bigdecimal"/utf8>>, function => <<"multiply_power_of_ten"/utf8>>, line => 275}) end, _pipe = bigi_ffi:from(10), _pipe@1 = bigi_ffi:power(_pipe, bigi_ffi:from(N)), _pipe@2 = gleam@result:lazy_unwrap(_pipe@1, fun() -> bigi_ffi:from(0) end), bigi_ffi:multiply(_pipe@2, Value). -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 84). -spec truncate_to_bigint(big_decimal()) -> bigi:big_int(). truncate_to_bigint(Value) -> _pipe = unscaled_value(Value), bigi_ffi:divide( _pipe, multiply_power_of_ten(bigi_ffi:from(1), scale(Value)) ). -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 130). -spec add_zeros(big_decimal(), integer(), integer()) -> big_decimal(). add_zeros(Value, New_scale, Scale_diff) -> _pipe = unscaled_value(Value), _pipe@1 = multiply_power_of_ten(_pipe, Scale_diff), {big_decimal, _pipe@1, New_scale}. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 182). -spec calculate_adjustment_for_half_round( bigi:big_int(), integer(), bigi:big_int(), bigi:big_int(), bigdecimal@rounding:rounding_mode() ) -> bigi:big_int(). calculate_adjustment_for_half_round( Unscaled_value, Sign, Quotient, Power_of_ten, Rounding ) -> Remainder = begin _pipe = bigi_ffi:multiply(Quotient, Power_of_ten), _pipe@1 = bigi_ffi:subtract(_pipe, Unscaled_value), erlang:abs(_pipe@1) end, To_compare = begin _pipe@2 = get_magnitude(Remainder, 0), multiply_power_of_ten(bigi_ffi:from(5), _pipe@2) end, case {bigi_ffi:compare(Remainder, To_compare), Rounding} of {eq, half_even} -> case is_even(Quotient) of true -> bigi_ffi:zero(); false -> bigi_ffi:from(Sign) end; {eq, half_up} -> bigi_ffi:from(Sign); {gt, _} -> bigi_ffi:from(Sign); {_, _} -> bigi_ffi:zero() end. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 156). -spec adjust_unscaled_value_for_rounding( bigi:big_int(), integer(), bigi:big_int(), bigi:big_int(), bigdecimal@rounding:rounding_mode() ) -> bigi:big_int(). adjust_unscaled_value_for_rounding( Unscaled_value, Quotient_sign, Quotient, Divisor, Rounding ) -> Adjustment = case {Rounding, Quotient_sign} of {floor, S} when S < 0 -> bigi_ffi:from(-1); {ceiling, S@1} when S@1 > 0 -> bigi_ffi:from(1); {up, S@2} -> bigi_ffi:from(S@2); {half_up, S@3} when S@3 =/= 0 -> calculate_adjustment_for_half_round( Unscaled_value, S@3, Quotient, Divisor, Rounding ); {half_down, S@3} when S@3 =/= 0 -> calculate_adjustment_for_half_round( Unscaled_value, S@3, Quotient, Divisor, Rounding ); {half_even, S@3} when S@3 =/= 0 -> calculate_adjustment_for_half_round( Unscaled_value, S@3, Quotient, Divisor, Rounding ); {_, _} -> bigi_ffi:zero() end, _pipe = Quotient, bigi_ffi:add(_pipe, Adjustment). -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 136). -spec rescale_with_rounding( big_decimal(), integer(), integer(), bigdecimal@rounding:rounding_mode() ) -> big_decimal(). rescale_with_rounding(Value, New_scale, Scale_diff, Rounding) -> Tens = multiply_power_of_ten(bigi_ffi:from(1), Scale_diff), Unscaled = unscaled_value(Value), Quotient = bigi_ffi:divide(Unscaled, Tens), _pipe = adjust_unscaled_value_for_rounding( Unscaled, signum(Value), Quotient, Tens, Rounding ), {big_decimal, _pipe, New_scale}. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 117). -spec rescale(big_decimal(), integer(), bigdecimal@rounding:rounding_mode()) -> big_decimal(). rescale(Value, New_scale, Rounding) -> Scale_diff = scale(Value) - New_scale, case gleam@int:compare(Scale_diff, 0) of eq -> Value; lt -> add_zeros(Value, New_scale, - Scale_diff); gt -> rescale_with_rounding(Value, New_scale, Scale_diff, Rounding) end. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 263). -spec scale_adjusted_add(big_decimal(), big_decimal(), integer()) -> big_decimal(). scale_adjusted_add(To_scale, To_add, Scale_difference) -> _pipe = unscaled_value(To_scale), _pipe@1 = multiply_power_of_ten(_pipe, Scale_difference), _pipe@2 = bigi_ffi:add(_pipe@1, unscaled_value(To_add)), {big_decimal, _pipe@2, scale(To_add)}. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 228). -spec add(big_decimal(), big_decimal()) -> big_decimal(). add(Augend, Addend) -> case gleam@int:subtract(scale(Augend), scale(Addend)) of Scale_difference when Scale_difference < 0 -> scale_adjusted_add(Augend, Addend, - Scale_difference); Scale_difference@1 when Scale_difference@1 > 0 -> scale_adjusted_add(Addend, Augend, Scale_difference@1); _ -> {big_decimal, bigi_ffi:add(unscaled_value(Augend), unscaled_value(Addend)), scale(Augend)} end. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 242). -spec sum(list(big_decimal())) -> big_decimal(). sum(Values) -> gleam@list:fold(Values, zero(), fun add/2). -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 249). -spec subtract(big_decimal(), big_decimal()) -> big_decimal(). subtract(Minuend, Subtrahend) -> case gleam@int:subtract(scale(Minuend), scale(Subtrahend)) of Scale_difference when Scale_difference < 0 -> scale_adjusted_add(Minuend, negate(Subtrahend), - Scale_difference); Scale_difference@1 when Scale_difference@1 > 0 -> scale_adjusted_add(negate(Subtrahend), Minuend, Scale_difference@1); _ -> {big_decimal, bigi_ffi:subtract( unscaled_value(Minuend), unscaled_value(Subtrahend) ), scale(Minuend)} end. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 297). -spec scale_adjusted_compare(big_decimal(), big_decimal(), integer()) -> gleam@order:order(). scale_adjusted_compare(To_scale, To_compare, Scale_difference) -> _assert_subject = begin _pipe = gleam@int:absolute_value(Scale_difference), _pipe@1 = bigi_ffi:from(_pipe), _pipe@2 = bigi_ffi:power(bigi_ffi:from(10), _pipe@1), _pipe@3 = gleam@result:map( _pipe@2, fun(_capture) -> bigi_ffi:multiply(_capture, unscaled_value(To_scale)) end ), gleam@result:map( _pipe@3, fun(_capture@1) -> bigi_ffi:compare(_capture@1, unscaled_value(To_compare)) end ) end, {ok, Compare_order} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail, module => <<"bigdecimal"/utf8>>, function => <<"scale_adjusted_compare"/utf8>>, line => 303}) end, Compare_order. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 286). -spec compare(big_decimal(), big_decimal()) -> gleam@order:order(). compare(This, That) -> case gleam@int:subtract(scale(This), scale(That)) of Scale_difference when Scale_difference < 0 -> scale_adjusted_compare(This, That, Scale_difference); Scale_difference@1 when Scale_difference@1 > 0 -> _pipe = scale_adjusted_compare(That, This, Scale_difference@1), gleam@order:negate(_pipe); _ -> bigi_ffi:compare(unscaled_value(This), unscaled_value(That)) end. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 92). -spec clamp(big_decimal(), big_decimal(), big_decimal()) -> big_decimal(). clamp(Value, Min, Max) -> case compare(Value, Min) of eq -> case gleam@int:compare(scale(Value), scale(Min)) of eq -> Value; gt -> Value; lt -> Min end; lt -> Min; gt -> case compare(Value, Max) of eq -> case gleam@int:compare(scale(Value), scale(Max)) of eq -> Value; lt -> Value; gt -> Max end; gt -> Max; lt -> Value end end. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 312). -spec multiply(big_decimal(), big_decimal()) -> big_decimal(). multiply(Multiplicand, Multiplier) -> {big_decimal, bigi_ffi:multiply( unscaled_value(Multiplicand), unscaled_value(Multiplier) ), gleam@int:add(scale(Multiplicand), scale(Multiplier))}. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 324). -spec product(list(big_decimal())) -> big_decimal(). product(Values) -> gleam@list:fold(Values, one(), fun multiply/2). -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 377). -spec divide_and_round( bigi:big_int(), bigi:big_int(), integer(), bigdecimal@rounding:rounding_mode() ) -> big_decimal(). divide_and_round(Dividend, Divisor, Scale, Rounding) -> Quotient = bigi_ffi:divide(Dividend, Divisor), Quotient_sign = begin _pipe = bigi_ffi:compare(Quotient, bigi_ffi:zero()), gleam@order:to_int(_pipe) end, Remainder = bigi_ffi:remainder(Dividend, Divisor), case bigi_ffi:compare(Remainder, bigi_ffi:zero()) of eq -> {big_decimal, Quotient, Scale}; lt -> _pipe@1 = adjust_unscaled_value_for_rounding( Dividend, Quotient_sign, Quotient, Divisor, Rounding ), {big_decimal, _pipe@1, Scale}; gt -> _pipe@1 = adjust_unscaled_value_for_rounding( Dividend, Quotient_sign, Quotient, Divisor, Rounding ), {big_decimal, _pipe@1, Scale} end. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 408). -spec trim_zeros_to_match_scale(big_decimal(), integer()) -> big_decimal(). trim_zeros_to_match_scale(Value, Preferred_scale) -> case scale(Value) > Preferred_scale of false -> Value; true -> Non_zero_remainder = begin _pipe = unscaled_value(Value), _pipe@1 = bigi_ffi:remainder(_pipe, bigi_ffi:from(10)), bigi_ffi:compare(_pipe@1, bigi_ffi:zero()) end /= eq, case Non_zero_remainder of true -> Value; false -> trim_zeros_to_match_scale( begin _pipe@2 = unscaled_value(Value), _pipe@3 = bigi_ffi:divide( _pipe@2, bigi_ffi:from(10) ), {big_decimal, _pipe@3, scale(Value) - 1} end, Preferred_scale ) end end. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 78). -spec trim_zeros(big_decimal()) -> big_decimal(). trim_zeros(Value) -> trim_zeros_to_match_scale(Value, 0). -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 348). -spec divide_internal( big_decimal(), big_decimal(), integer(), bigdecimal@rounding:rounding_mode() ) -> big_decimal(). divide_internal(Dividend, Divisor, Preferred_scale, Rounding) -> New_scale = begin _pipe = (10 * precision(Divisor)), _pipe@1 = gleam@int:to_float(_pipe), _pipe@2 = gleam@float:divide(_pipe@1, 3.0), _pipe@3 = gleam@result:lazy_unwrap(_pipe@2, fun() -> +0.0 end), _pipe@4 = gleam@float:ceiling(_pipe@3), _pipe@5 = gleam@float:round(_pipe@4), gleam@int:add(_pipe@5, precision(Dividend)) end, _pipe@10 = case (scale(Divisor) - scale(Dividend)) + New_scale of X when X > 0 -> _pipe@6 = unscaled_value(Dividend), _pipe@7 = multiply_power_of_ten(_pipe@6, X), divide_and_round( _pipe@7, unscaled_value(Divisor), New_scale, Rounding ); X@1 -> _pipe@8 = unscaled_value(Divisor), _pipe@9 = multiply_power_of_ten(_pipe@8, - X@1), divide_and_round( unscaled_value(Dividend), _pipe@9, New_scale, Rounding ) end, trim_zeros_to_match_scale(_pipe@10, Preferred_scale). -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 335). -spec divide(big_decimal(), big_decimal(), bigdecimal@rounding:rounding_mode()) -> big_decimal(). divide(Dividend, Divisor, Rounding) -> New_scale = scale(Dividend) - scale(Divisor), case {signum(Dividend), signum(Divisor)} of {_, 0} -> zero(); {0, _} -> {big_decimal, bigi_ffi:from(0), New_scale}; {_, _} -> divide_internal(Dividend, Divisor, New_scale, Rounding) end. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 435). -spec power(big_decimal(), integer()) -> {ok, big_decimal()} | {error, nil}. power(Value, Exponent) -> _pipe = unscaled_value(Value), _pipe@1 = bigi_ffi:power(_pipe, bigi_ffi:from(Exponent)), gleam@result:map( _pipe@1, fun(_capture) -> {big_decimal, _capture, gleam@int:multiply(scale(Value), Exponent)} end ). -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 475). -spec parse_unscaled(binary(), integer()) -> {ok, big_decimal()} | {error, nil}. parse_unscaled(Value, Scale) -> _pipe = bigi_ffi:from_string(Value), gleam@result:map(_pipe, fun(_capture) -> {big_decimal, _capture, Scale} end). -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 466). -spec parse_decimal(binary(), integer()) -> {ok, big_decimal()} | {error, nil}. parse_decimal(Value, Initial_scale) -> case begin _pipe = Value, gleam@string:split_once(_pipe, <<"."/utf8>>) end of {ok, {Before, After}} -> parse_unscaled( <>, erlang:byte_size(After) + Initial_scale ); {error, _} -> parse_unscaled(Value, Initial_scale) end. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 454). -spec parse_exponential(binary()) -> {ok, big_decimal()} | {error, nil}. parse_exponential(Value) -> Value@1 = begin _pipe = Value, _pipe@1 = gleam@string:trim(_pipe), gleam@string:lowercase(_pipe@1) end, case begin _pipe@2 = Value@1, gleam@string:split_once(_pipe@2, <<"e"/utf8>>) end of {ok, {Number, Exponent}} -> _pipe@3 = gleam@int:parse(Exponent), _pipe@4 = gleam@result:map(_pipe@3, fun gleam@int:negate/1), gleam@result:'try'( _pipe@4, fun(_capture) -> parse_decimal(Number, _capture) end ); {error, _} -> parse_decimal(Value@1, 0) end. -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 450). -spec from_string(binary()) -> {ok, big_decimal()} | {error, nil}. from_string(Value) -> parse_exponential(Value). -file("/Users/horvath.andris/Developer/bigdecimal/src/bigdecimal.gleam", 441). -spec from_float(float()) -> big_decimal(). from_float(Value) -> _assert_subject = begin _pipe = gleam@float:to_string(Value), from_string(_pipe) end, {ok, Bigd} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail, module => <<"bigdecimal"/utf8>>, function => <<"from_float"/utf8>>, line => 443}) end, Bigd.