_site/cover/msmp_decimal.COVER.html

1 %% Copyright (c) 2023 Peter Morgan <peter.james.morgan@gmail.com>
2 %%
3 %% Licensed under the Apache License, Version 2.0 (the "License");
4 %% you may not use this file except in compliance with the License.
5 %% You may obtain a copy of the License at
6 %%
7 %% http://www.apache.org/licenses/LICENSE-2.0
8 %%
9 %% Unless required by applicable law or agreed to in writing, software
10 %% distributed under the License is distributed on an "AS IS" BASIS,
11 %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 %% See the License for the specific language governing permissions and
13 %% limitations under the License.
14
15
16 -module(msmp_decimal).
17
18
19 -export([decode/2]).
20 -export([packed_byte_size/2]).
21 -import(scran_bytes, [take/1]).
22 -import(scran_combinator, [map_result/2]).
23 -include_lib("kernel/include/logger.hrl").
24
25
26 decode(Precision, Scale) ->
27 16 IntegerBytes = packed_byte_size(Precision - Scale),
28 16 LeftoverBytes = leftover_bytes(Precision - Scale),
29 16 FullBytes = full_bytes(Precision - Scale),
30
31 16 FractionBytes = packed_byte_size(Scale),
32
33 16 fun
34 (Input) ->
35
36 16 ?LOG_DEBUG(#{integer_bytes => IntegerBytes,
37 leftover_bytes => LeftoverBytes,
38 full_bytes => FullBytes,
39 input => Input,
40 16 fraction_bytes => FractionBytes}),
41
42 16 (map_result(
43 take(packed_byte_size(Precision, Scale)),
44 fun
45 (<<1:1,
46 Leftover:(LeftoverBytes * 8 - 1),
47 Full:FullBytes/unit:8,
48 Fraction:FractionBytes/unit:8>>) when FullBytes > 0 ->
49 4 ?LOG_DEBUG(#{left_over => Leftover,
50 full => Full,
51 4 fraction => Fraction}),
52 4 {list_to_integer(integer_to_list(Leftover) ++ integer_to_list(Full)), Fraction};
53
54
55 (<<1:1,
56 Leftover:(LeftoverBytes * 8 - 1),
57 Fraction:FractionBytes/unit:8>>) ->
58 6 ?LOG_DEBUG(#{leftover => Leftover,
59 6 fraction => Fraction}),
60 6 {Leftover, Fraction};
61
62
63 (<<0:1, _/bits>> = Negated) when FullBytes > 0 ->
64 2 <<_:1,
65 Leftover:(LeftoverBytes * 8 - 1),
66 Full:FullBytes/unit:8,
67 Fraction:FractionBytes/unit:8>> = flip(Negated),
68
69 2 ?LOG_DEBUG(#{negated => Negated,
70 leftover => Leftover,
71 full => Full,
72 2 fraction => Fraction}),
73 2 {-list_to_integer(integer_to_list(Leftover) ++ integer_to_list(Full)), Fraction};
74
75
76 (<<0:1, _/bits>> = Negated) ->
77 4 <<_:1,
78 Leftover:(LeftoverBytes * 8 - 1),
79 Fraction:FractionBytes/unit:8>> = flip(Negated),
80
81 4 ?LOG_DEBUG(#{negated => Negated,
82 leftover => Leftover,
83 4 fraction => Fraction}),
84 4 {-Leftover, Fraction}
85 end))(Input)
86 end.
87
88
89 flip(Bytes) ->
90 6 list_to_binary([<<(bnot Byte):8>> || <<Byte:8>> <= Bytes]).
91
92
93 packed_byte_size(Precision, Scale) when Precision > Scale ->
94 20 ?FUNCTION_NAME(Precision - Scale) + ?FUNCTION_NAME(Scale).
95
96 packed_byte_size(Digits) ->
97 72 full_bytes(Digits) + leftover_bytes(Digits).
98
99
100 full_bytes(Digits) ->
101 88 (Digits div 9) * 4.
102
103
104 leftover_bytes(Digits) when Digits rem 9 == 0 ->
105 2 0;
106 leftover_bytes(Digits) when Digits rem 9 =< 2 ->
107 44 1;
108 leftover_bytes(Digits) when Digits rem 9 =< 4 ->
109 40 2;
110 leftover_bytes(Digits) when Digits rem 9 =< 6 ->
111 2 3;
112 leftover_bytes(Digits) when Digits rem 9 =< 8 ->
113
:-(
4.
Line Hits Source