1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.ss.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.math.BigInteger;
import org.junit.jupiter.api.Test;
/**
* Tests for {@link ExpandedDouble}
*/
public final class TestExpandedDouble {
private static final BigInteger BIG_POW_10 = BigInteger.valueOf(1000000000);
@Test
public void testNegative() {
ExpandedDouble hd = new ExpandedDouble(0xC010000000000000L);
assertNotEquals(-2046, hd.getBinaryExponent(), "identified bug - sign bit not masked out of exponent");
assertEquals(2, hd.getBinaryExponent());
BigInteger frac = hd.getSignificand();
assertEquals(64, frac.bitLength());
assertEquals(1, frac.bitCount());
}
@Test
public void testSubnormal() {
ExpandedDouble hd = new ExpandedDouble(0x0000000000000001L);
assertNotEquals(-1023, hd.getBinaryExponent(), "identified bug - subnormal numbers not decoded properly");
assertEquals(-1086, hd.getBinaryExponent());
BigInteger frac = hd.getSignificand();
assertEquals(64, frac.bitLength());
assertEquals(1, frac.bitCount());
}
/**
* Tests specific values for conversion from {@link ExpandedDouble} to {@link NormalisedDecimal} and back
*/
@Test
public void testRoundTripShifting() {
long[] rawValues = {
0x4010000000000004L,
0x7010000000000004L,
0x1010000000000004L,
0x0010000000000001L, // near lowest normal number
0x0010000000000000L, // lowest normal number
0x000FFFFFFFFFFFFFL, // highest subnormal number
0x0008000000000000L, // subnormal number
0xC010000000000004L,
0xE230100010001004L,
0x403CE0FFFFFFFFF2L,
0x0000000000000001L, // smallest non-zero number (subnormal)
0x6230100010000FFEL,
0x6230100010000FFFL,
0x6230100010001000L,
0x403CE0FFFFFFFFF0L, // has single digit round trip error
0x2B2BFFFF10001079L,
};
for (int i = 0; i < rawValues.length; i++) {
confirmRoundTrip(i, rawValues[i]);
}
}
public static void confirmRoundTrip(int i, long rawBitsA) {
double a = Double.longBitsToDouble(rawBitsA);
if (a == 0.0) {
// Can't represent 0.0 or -0.0 with NormalisedDecimal
return;
}
ExpandedDouble ed1 = new ExpandedDouble(rawBitsA);
NormalisedDecimal nd2 = ed1.normaliseBaseTen();
checkNormaliseBaseTenResult(ed1, nd2);
ExpandedDouble ed3 = nd2.normaliseBaseTwo();
assertEquals(ed3.getBinaryExponent(), ed1.getBinaryExponent(), "bin exp mismatch");
BigInteger diff = ed3.getSignificand().subtract(ed1.getSignificand()).abs();
if (diff.signum() == 0) {
return;
}
// original quantity only has 53 bits of precision
// these quantities may have errors in the 64th bit, which hopefully don't make any difference
// errors in the 64th bit happen from time to time
// this is well below the 53 bits of precision required
assertTrue(diff.bitLength() < 2);
}
private static void checkNormaliseBaseTenResult(ExpandedDouble orig, NormalisedDecimal result) {
String sigDigs = result.getSignificantDecimalDigits();
BigInteger frac = orig.getSignificand();
while (frac.bitLength() + orig.getBinaryExponent() < 200) {
frac = frac.multiply(BIG_POW_10);
}
int binaryExp = orig.getBinaryExponent() - orig.getSignificand().bitLength();
String origDigs = frac.shiftLeft(binaryExp+1).toString(10);
assertTrue(origDigs.startsWith(sigDigs));
double dO = Double.parseDouble("0." + origDigs.substring(sigDigs.length()));
double d1 = Double.parseDouble(result.getFractionalPart().toPlainString());
BigInteger subDigsO = BigInteger.valueOf((int) (dO * 32768 + 0.5));
BigInteger subDigsB = BigInteger.valueOf((int) (d1 * 32768 + 0.5));
if (subDigsO.equals(subDigsB)) {
return;
}
BigInteger diff = subDigsB.subtract(subDigsO).abs();
// 100/32768 ~= 0.003
assertTrue(diff.intValue() <= 100, "minor mistake");
}
}
|