1
1
defmodule BSON.Decimal128 do
2
+
3
+ @ moduledoc """
4
+ see https://en.wikipedia.org/wiki/Decimal128_floating-point_format
5
+ """
6
+
2
7
use Bitwise
3
8
4
9
@ signed_bit_mask 1 <<< 63
@@ -9,13 +14,20 @@ defmodule BSON.Decimal128 do
9
14
@ exponent_bias 6176
10
15
@ max_exponent 6111
11
16
@ min_exponent - 6176
17
+ @ s_nan_mask 0x1 <<< 57
18
+ @ significand_mask ( ( 0x1 <<< 49 ) - 1 )
19
+ @ low_mask 0xffffffffffffffff
12
20
13
21
def decode ( << _ :: little - 64 , high :: little - 64 >> = bits ) do
14
22
is_negative = ( high &&& @ signed_bit_mask ) == ( @ signed_bit_mask )
15
23
combination = ( high >>> 58 &&& @ combination_mask )
16
24
two_highest_bits_set = combination >>> 3 == 3
17
25
is_infinity = two_highest_bits_set && combination == @ combintation_infinity
18
- is_nan = two_highest_bits_set && combination == @ combintation_nan
26
+ is_nan = case { ( two_highest_bits_set && combination ) == @ combintation_nan , ( high &&& @ s_nan_mask ) == @ s_nan_mask } do
27
+ { true , true } -> :sNan
28
+ { true , false } -> :qNan
29
+ _ -> false
30
+ end
19
31
20
32
exponent = exponent ( high , two_highest_bits_set )
21
33
@@ -29,10 +41,35 @@ defmodule BSON.Decimal128 do
29
41
)
30
42
end
31
43
44
+ @ doc """
45
+ s 11110 xx...x ±infinity
46
+ s 11111 0x...x a quiet NaN
47
+ s 11111 1x...x a signalling NaN
48
+ """
49
+ def encode ( % Decimal { sign: - 1 , coef: :inf } ) do
50
+ low = 0
51
+ high = 0x3e <<< 58
52
+ << low :: little - 64 , high :: little - 64 >>
53
+ end
54
+ def encode ( % Decimal { coef: :inf } ) do
55
+ low = 0
56
+ high = 0x1e <<< 58
57
+ << low :: little - 64 , high :: little - 64 >>
58
+ end
59
+ def encode ( % Decimal { coef: :qNaN } ) do
60
+ low = 0
61
+ high = 0x1f <<< 58
62
+ << low :: little - 64 , high :: little - 64 >>
63
+ end
64
+ def encode ( % Decimal { coef: :sNaN } ) do
65
+ low = 0
66
+ high = 0x3f <<< 57
67
+ << low :: little - 64 , high :: little - 64 >>
68
+ end
32
69
def encode ( % Decimal { sign: sign , coef: significand , exp: exponent } ) when exponent >= @ min_exponent and exponent <= @ max_exponent do
33
70
biasedExponent = exponent + @ exponent_bias
34
- low = significand &&& 0xffffffff
35
- high = ( significand >>> 64 ) &&& 0xffffffff
71
+ low = significand &&& @ low_mask
72
+ high = ( significand >>> 64 ) &&& @ significand_mask ## mask max significand
36
73
high = bor ( high , biasedExponent <<< 49 )
37
74
high = case sign do
38
75
1 -> high
@@ -41,7 +78,6 @@ defmodule BSON.Decimal128 do
41
78
42
79
<< low :: little - 64 , high :: little - 64 >>
43
80
end
44
-
45
81
def encode ( % Decimal { exp: exponent } ) do
46
82
message = "Exponent is out of range for Decimal128 encoding, #{ exponent } "
47
83
raise ArgumentError , message
@@ -51,7 +87,6 @@ defmodule BSON.Decimal128 do
51
87
biased_exponent = ( high >>> 47 ) &&& @ exponent_mask
52
88
biased_exponent - @ exponent_bias
53
89
end
54
-
55
90
defp exponent ( high , _two_highest_bits_not_set ) do
56
91
biased_exponent = ( high >>> 49 ) &&& @ exponent_mask
57
92
biased_exponent - @ exponent_bias
@@ -60,23 +95,21 @@ defmodule BSON.Decimal128 do
60
95
defp value ( % { is_negative: true , is_infinity: true } , _ , _ ) do
61
96
% Decimal { sign: - 1 , coef: :inf }
62
97
end
63
-
64
98
defp value ( % { is_negative: false , is_infinity: true } , _ , _ ) do
65
99
% Decimal { coef: :inf }
66
100
end
67
-
68
- defp value ( % { is_nan: true } , _ , _ ) do
101
+ defp value ( % { is_nan: :qNan } , _ , _ ) do
69
102
% Decimal { coef: :qNaN }
70
103
end
71
-
104
+ defp value ( % { is_nan: :sNan } , _ , _ ) do
105
+ % Decimal { coef: :sNaN }
106
+ end
72
107
defp value ( % { two_highest_bits_set: true } , _ , _ ) do
73
108
% Decimal { sign: 0 , coef: 0 , exp: 0 }
74
109
end
75
-
76
110
defp value ( % { is_negative: true } , coef , exponent ) do
77
111
% Decimal { sign: - 1 , coef: coef , exp: exponent }
78
112
end
79
-
80
113
defp value ( _ , coef , exponent ) do
81
114
% Decimal { coef: coef , exp: exponent }
82
115
end
0 commit comments