Skip to content

Commit 3bfd4d5

Browse files
committed
Add conversion from BigInteger, both with rounding, and exact fit
+ Document fact parseBytes expects network byte-order, and toBytes produces network byte-order
1 parent 8d2bba9 commit 3bfd4d5

File tree

9 files changed

+538
-1
lines changed

9 files changed

+538
-1
lines changed

src/main/java/org/firebirdsql/decimal/Decimal.java

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
package org.firebirdsql.decimal;
2323

2424
import java.math.BigDecimal;
25+
import java.math.BigInteger;
2526

2627
import static java.util.Objects.requireNonNull;
2728

@@ -102,7 +103,11 @@ public final double doubleValue() {
102103
}
103104

104105
/**
105-
* Converts this decimal to its IEEE-754 byte encoding.
106+
* Converts this decimal to its IEEE-754 byte encoding in network byte-order (aka big-endian).
107+
* <p>
108+
* This method returns network byte-order (aka big-endian). When you need little-endian order, you will need to
109+
* reverse the bytes in the array.
110+
* </p>
106111
*
107112
* @return byte array
108113
*/
@@ -308,6 +313,42 @@ final T valueOf(BigDecimal value, OverflowHandling overflowHandling) {
308313
return createDecimal(value.signum(), roundedValue);
309314
}
310315

316+
/**
317+
* Creates a decimal from {@code value}, applying rounding where necessary.
318+
* <p>
319+
* Values exceeding the range of this type will be handled according to the specified overflow handling.
320+
* </p>
321+
* <p>
322+
* Calling this method is equivalent to {@code valueOf(new BigDecimal(value), overflowHandling)}.
323+
* </p>
324+
*
325+
* @param value
326+
* Big integer value to convert
327+
* @param overflowHandling
328+
* Handling of overflows
329+
* @return Decimal equivalent
330+
* @throws DecimalOverflowException
331+
* If {@code OverflowHandling#THROW_EXCEPTION} and the value is out of range.
332+
* @see #valueOfExact(BigInteger)
333+
*/
334+
final T valueOf(BigInteger value, OverflowHandling overflowHandling) {
335+
return valueOf(new BigDecimal(value), overflowHandling);
336+
}
337+
338+
/**
339+
* Creates a decimal from {@code value}, rejecting values that would lose precision due to rounding.
340+
*
341+
* @param value Big integer value to convert
342+
* @throws DecimalOverflowException
343+
* If the value is out of range.
344+
* @return Decimal equivalent
345+
* @see #valueOf(BigInteger, OverflowHandling)
346+
*/
347+
final T valueOfExact(BigInteger value) {
348+
final BigDecimal bigDecimal = new BigDecimal(decimalFormat.validateCoefficient(value));
349+
return createDecimal(value.signum(), bigDecimal);
350+
}
351+
311352
/**
312353
* Creates a decimal from {@code value}, applying rounding where necessary.
313354
* <p>

src/main/java/org/firebirdsql/decimal/Decimal128.java

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
package org.firebirdsql.decimal;
2323

2424
import java.math.BigDecimal;
25+
import java.math.BigInteger;
2526

2627
/**
2728
* An IEEE-754 Decimal128.
@@ -58,6 +59,19 @@ DecimalFactory<Decimal128> getDecimalFactory() {
5859
return DECIMAL_128_FACTORY;
5960
}
6061

62+
/**
63+
* Parses the provided byte array to a {@code Decimal128}.
64+
* <p>
65+
* This method parses network byte-order (aka big-endian). When using little-endian order, you will need to
66+
* reverse the bytes in the array first.
67+
* </p>
68+
*
69+
* @param decBytes
70+
* Bytes of the Decimal128 value in network byte-order (aka big-endian)
71+
* @return Instance of {@code Decimal128}
72+
* @throws IllegalArgumentException
73+
* When {@code decBytes} is not 16 bytes long
74+
*/
6175
public static Decimal128 parseBytes(final byte[] decBytes) {
6276
return DECIMAL_128_CODEC.parseBytes(decBytes);
6377
}
@@ -94,6 +108,55 @@ public static Decimal128 valueOf(final BigDecimal value, final OverflowHandling
94108
return DECIMAL_128_FACTORY.valueOf(value, overflowHandling);
95109
}
96110

111+
/**
112+
* Creates a {@code Decimal128} from {@code value}, applying rounding where necessary.
113+
* <p>
114+
* Values exceeding the range of this type will be returned as +/-Infinity.
115+
* </p>
116+
*
117+
* @param value
118+
* Big integer value to convert
119+
* @return Decimal128 equivalent
120+
*/
121+
public static Decimal128 valueOf(final BigInteger value) {
122+
return valueOf(value, OverflowHandling.ROUND_TO_INFINITY);
123+
}
124+
125+
/**
126+
* Creates a {@code Decimal128} from {@code value}, applying rounding where necessary.
127+
* <p>
128+
* Values exceeding the range of this type will be handled according to the specified overflow handling.
129+
* </p>
130+
* <p>
131+
* Calling this method is equivalent to {@code valueOf(new BigDecimal(value), overflowHandling)}.
132+
* </p>
133+
*
134+
* @param value
135+
* Big integer value to convert
136+
* @param overflowHandling
137+
* Handling of overflows
138+
* @return Decimal128 equivalent
139+
* @throws DecimalOverflowException
140+
* If {@code OverflowHandling#THROW_EXCEPTION} and the value is out of range.
141+
* @see #valueOfExact(BigInteger)
142+
*/
143+
public static Decimal128 valueOf(final BigInteger value, final OverflowHandling overflowHandling) {
144+
return DECIMAL_128_FACTORY.valueOf(value, overflowHandling);
145+
}
146+
147+
/**
148+
* Creates a {@code Decimal128} from {@code value}, rejecting values that would lose precision due to rounding.
149+
*
150+
* @param value Big integer value to convert
151+
* @throws DecimalOverflowException
152+
* If the value is out of range.
153+
* @return Decimal128 equivalent
154+
* @see #valueOf(BigInteger, OverflowHandling)
155+
*/
156+
public static Decimal128 valueOfExact(final BigInteger value) {
157+
return DECIMAL_128_FACTORY.valueOfExact(value);
158+
}
159+
97160
/**
98161
* Creates a {@code Decimal128} from {@code value}, applying rounding where necessary.
99162
* <p>

src/main/java/org/firebirdsql/decimal/Decimal32.java

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
package org.firebirdsql.decimal;
2323

2424
import java.math.BigDecimal;
25+
import java.math.BigInteger;
2526

2627
/**
2728
* An IEEE-754 Decimal32.
@@ -58,6 +59,19 @@ DecimalFactory<Decimal32> getDecimalFactory() {
5859
return DECIMAL_32_FACTORY;
5960
}
6061

62+
/**
63+
* Parses the provided byte array to a {@code Decimal32}.
64+
* <p>
65+
* This method parses network byte-order (aka big-endian). When using little-endian order, you will need to
66+
* reverse the bytes in the array first.
67+
* </p>
68+
*
69+
* @param decBytes
70+
* Bytes of the Decimal32 value in network byte-order (aka big-endian)
71+
* @return Instance of {@code Decimal32}
72+
* @throws IllegalArgumentException
73+
* When {@code decBytes} is not 4 bytes long
74+
*/
6175
public static Decimal32 parseBytes(final byte[] decBytes) {
6276
return DECIMAL_32_CODEC.parseBytes(decBytes);
6377
}
@@ -94,6 +108,55 @@ public static Decimal32 valueOf(final BigDecimal value, final OverflowHandling o
94108
return DECIMAL_32_FACTORY.valueOf(value, overflowHandling);
95109
}
96110

111+
/**
112+
* Creates a {@code Decimal32} from {@code value}, applying rounding where necessary.
113+
* <p>
114+
* Values exceeding the range of this type will be returned as +/-Infinity.
115+
* </p>
116+
*
117+
* @param value
118+
* Big integer value to convert
119+
* @return Decimal32 equivalent
120+
*/
121+
public static Decimal32 valueOf(final BigInteger value) {
122+
return valueOf(value, OverflowHandling.ROUND_TO_INFINITY);
123+
}
124+
125+
/**
126+
* Creates a {@code Decimal32} from {@code value}, applying rounding where necessary.
127+
* <p>
128+
* Values exceeding the range of this type will be handled according to the specified overflow handling.
129+
* </p>
130+
* <p>
131+
* Calling this method is equivalent to {@code valueOf(new BigDecimal(value), overflowHandling)}.
132+
* </p>
133+
*
134+
* @param value
135+
* Big integer value to convert
136+
* @param overflowHandling
137+
* Handling of overflows
138+
* @return Decimal32 equivalent
139+
* @throws DecimalOverflowException
140+
* If {@code OverflowHandling#THROW_EXCEPTION} and the value is out of range.
141+
* @see #valueOfExact(BigInteger)
142+
*/
143+
public static Decimal32 valueOf(final BigInteger value, final OverflowHandling overflowHandling) {
144+
return DECIMAL_32_FACTORY.valueOf(value, overflowHandling);
145+
}
146+
147+
/**
148+
* Creates a {@code Decimal32} from {@code value}, rejecting values that would lose precision due to rounding.
149+
*
150+
* @param value Big integer value to convert
151+
* @throws DecimalOverflowException
152+
* If the value is out of range.
153+
* @return Decimal32 equivalent
154+
* @see #valueOf(BigInteger, OverflowHandling)
155+
*/
156+
public static Decimal32 valueOfExact(final BigInteger value) {
157+
return DECIMAL_32_FACTORY.valueOfExact(value);
158+
}
159+
97160
/**
98161
* Creates a {@code Decimal32} from {@code value}, applying rounding where necessary.
99162
* <p>

src/main/java/org/firebirdsql/decimal/Decimal64.java

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
package org.firebirdsql.decimal;
2323

2424
import java.math.BigDecimal;
25+
import java.math.BigInteger;
2526

2627
/**
2728
* An IEEE-754 Decimal64.
@@ -58,6 +59,19 @@ DecimalFactory<Decimal64> getDecimalFactory() {
5859
return DECIMAL_64_FACTORY;
5960
}
6061

62+
/**
63+
* Parses the provided byte array to a {@code Decimal64}.
64+
* <p>
65+
* This method parses network byte-order (aka big-endian). When using little-endian order, you will need to
66+
* reverse the bytes in the array first.
67+
* </p>
68+
*
69+
* @param decBytes
70+
* Bytes of the Decimal64 value in network byte-order (aka big-endian)
71+
* @return Instance of {@code Decimal64}
72+
* @throws IllegalArgumentException
73+
* When {@code decBytes} is not 8 bytes long
74+
*/
6175
public static Decimal64 parseBytes(final byte[] decBytes) {
6276
return DECIMAL_64_CODEC.parseBytes(decBytes);
6377
}
@@ -94,6 +108,55 @@ public static Decimal64 valueOf(final BigDecimal value, final OverflowHandling o
94108
return DECIMAL_64_FACTORY.valueOf(value, overflowHandling);
95109
}
96110

111+
/**
112+
* Creates a {@code Decimal64} from {@code value}, applying rounding where necessary.
113+
* <p>
114+
* Values exceeding the range of this type will be returned as +/-Infinity.
115+
* </p>
116+
*
117+
* @param value
118+
* Big integer value to convert
119+
* @return Decimal64 equivalent
120+
*/
121+
public static Decimal64 valueOf(final BigInteger value) {
122+
return valueOf(value, OverflowHandling.ROUND_TO_INFINITY);
123+
}
124+
125+
/**
126+
* Creates a {@code Decimal64} from {@code value}, applying rounding where necessary.
127+
* <p>
128+
* Values exceeding the range of this type will be handled according to the specified overflow handling.
129+
* </p>
130+
* <p>
131+
* Calling this method is equivalent to {@code valueOf(new BigDecimal(value), overflowHandling)}.
132+
* </p>
133+
*
134+
* @param value
135+
* Big integer value to convert
136+
* @param overflowHandling
137+
* Handling of overflows
138+
* @return Decimal64 equivalent
139+
* @throws DecimalOverflowException
140+
* If {@code OverflowHandling#THROW_EXCEPTION} and the value is out of range.
141+
* @see #valueOfExact(BigInteger)
142+
*/
143+
public static Decimal64 valueOf(final BigInteger value, final OverflowHandling overflowHandling) {
144+
return DECIMAL_64_FACTORY.valueOf(value, overflowHandling);
145+
}
146+
147+
/**
148+
* Creates a {@code Decimal64} from {@code value}, rejecting values that would lose precision due to rounding.
149+
*
150+
* @param value Big integer value to convert
151+
* @throws DecimalOverflowException
152+
* If the value is out of range.
153+
* @return Decimal64 equivalent
154+
* @see #valueOf(BigInteger, OverflowHandling)
155+
*/
156+
public static Decimal64 valueOfExact(final BigInteger value) {
157+
return DECIMAL_64_FACTORY.valueOfExact(value);
158+
}
159+
97160
/**
98161
* Creates a {@code Decimal64} from {@code value}, applying rounding where necessary.
99162
* <p>

src/main/java/org/firebirdsql/decimal/DecimalFormat.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,26 @@ final BigDecimal validate(BigDecimal value) {
140140
return value;
141141
}
142142

143+
/**
144+
* Validates if the provided coefficient is in range for this decimal format.
145+
* <p>
146+
* Implementation note: this method is only used for validation in {@code valueOfExact(BigInteger)} methods.
147+
* </p>
148+
*
149+
* @param coefficient
150+
* Coefficient to check
151+
* @return coefficient if validation succeeded
152+
* @throws DecimalOverflowException
153+
* If the coefficient is out of range
154+
*/
155+
final BigInteger validateCoefficient(BigInteger coefficient) {
156+
if (maxCoefficient.compareTo(coefficient) < 0 || minCoefficient.compareTo(coefficient) > 0) {
157+
throw new DecimalOverflowException("Value " + coefficient + " is out of range for this type "
158+
+ "[" + minCoefficient + ", " + maxCoefficient + "]");
159+
}
160+
return coefficient;
161+
}
162+
143163
/**
144164
* Checks if the current precision or scale of the provided value is out of range for this decimal format.
145165
* <p>

0 commit comments

Comments
 (0)