001/*
002 * The MIT License (MIT)
003 *
004 * Copyright (c) 2015-2024 decimal4j (tools4j), Marco Terzer
005 *
006 * Permission is hereby granted, free of charge, to any person obtaining a copy
007 * of this software and associated documentation files (the "Software"), to deal
008 * in the Software without restriction, including without limitation the rights
009 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
010 * copies of the Software, and to permit persons to whom the Software is
011 * furnished to do so, subject to the following conditions:
012 *
013 * The above copyright notice and this permission notice shall be included in all
014 * copies or substantial portions of the Software.
015 *
016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
017 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
018 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
019 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
020 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
021 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
022 * SOFTWARE.
023 */
024package org.decimal4j.immutable;
025
026import java.math.BigDecimal;
027import java.math.BigInteger;
028import java.math.RoundingMode;
029
030import org.decimal4j.api.Decimal;
031import org.decimal4j.api.DecimalArithmetic;
032import org.decimal4j.base.AbstractImmutableDecimal;
033import org.decimal4j.exact.Multipliable18f;
034import org.decimal4j.factory.Factory18f;
035import org.decimal4j.mutable.MutableDecimal18f;
036import org.decimal4j.scale.Scale18f;
037
038/**
039 * <code>Decimal18f</code> represents an immutable decimal number with a fixed
040 * number of 18 digits to the right of the decimal point.
041 * <p>
042 * All methods for this class throw {@code NullPointerException} when passed a
043 * {@code null} object reference for any input parameter.
044 */
045public final class Decimal18f extends AbstractImmutableDecimal<Scale18f, Decimal18f> {
046
047        private static final long serialVersionUID = 1L;
048
049        /** Scale value 18 for {@code Decimal18f} returned by {@link #getScale()}.*/
050        public static final int SCALE = 18;
051
052        /** Scale metrics constant for {@code Decimal18f} returned by {@link #getScaleMetrics()}.*/
053        public static final Scale18f METRICS = Scale18f.INSTANCE;
054
055        /** Factory constant for {@code Decimal18f} returned by {@link #getFactory()}.*/
056        public static final Factory18f FACTORY = Factory18f.INSTANCE;
057        
058        /**
059         * Default arithmetic for {@code Decimal18f} performing unchecked operations with rounding mode 
060         * {@link RoundingMode#HALF_UP HALF_UP}.
061         */
062        public static final DecimalArithmetic DEFAULT_ARITHMETIC = METRICS.getDefaultArithmetic();
063        
064        /**
065         * Default arithmetic for {@code Decimal18f} performing checked operations with rounding mode 
066         * {@link RoundingMode#HALF_UP HALF_UP}.
067         */
068        public static final DecimalArithmetic DEFAULT_CHECKED_ARITHMETIC = METRICS.getDefaultCheckedArithmetic();
069
070        /** The unscaled long value that represents one.*/
071        public static final long ONE_UNSCALED = METRICS.getScaleFactor();
072
073        /** The {@code Decimal18f} constant zero.*/
074        public static final Decimal18f ZERO = new Decimal18f(0);
075    /**
076     * A constant holding the smallest positive value a {@code Decimal18f}
077     * can have, 10<sup>-18</sup>.
078     */
079        public static final Decimal18f ULP = new Decimal18f(1);
080
081    /**
082     * Initialize static constant array when class is loaded.
083     */
084    private static final int MAX_CONSTANT = 9;
085    private static final Decimal18f POS_CONST[] = new Decimal18f[MAX_CONSTANT+1];
086    private static final Decimal18f NEG_CONST[] = new Decimal18f[MAX_CONSTANT+1];
087
088    static {
089        for (int i = 1; i <= MAX_CONSTANT; i++) {
090            POS_CONST[i] = new Decimal18f(ONE_UNSCALED * i);
091            NEG_CONST[i] = new Decimal18f(-ONE_UNSCALED * i);
092        }
093    }
094
095        /** The {@code Decimal18f} constant 1.*/
096        public static final Decimal18f ONE = valueOf(1);
097        /** The {@code Decimal18f} constant 2.*/
098        public static final Decimal18f TWO = valueOf(2);
099        /** The {@code Decimal18f} constant 3.*/
100        public static final Decimal18f THREE = valueOf(3);
101        /** The {@code Decimal18f} constant 4.*/
102        public static final Decimal18f FOUR = valueOf(4);
103        /** The {@code Decimal18f} constant 5.*/
104        public static final Decimal18f FIVE = valueOf(5);
105        /** The {@code Decimal18f} constant 6.*/
106        public static final Decimal18f SIX = valueOf(6);
107        /** The {@code Decimal18f} constant 7.*/
108        public static final Decimal18f SEVEN = valueOf(7);
109        /** The {@code Decimal18f} constant 8.*/
110        public static final Decimal18f EIGHT = valueOf(8);
111        /** The {@code Decimal18f} constant 9.*/
112        public static final Decimal18f NINE = valueOf(9);
113
114        /** The {@code Decimal18f} constant -1.*/
115        public static final Decimal18f MINUS_ONE = valueOf(-1);
116
117        /** The {@code Decimal18f} constant 0.5.*/
118        public static final Decimal18f HALF = new Decimal18f(ONE_UNSCALED / 2);
119        /** The {@code Decimal18f} constant 0.1.*/
120        public static final Decimal18f TENTH = new Decimal18f(ONE_UNSCALED / 10);
121        /** The {@code Decimal18f} constant 0.01.*/
122        public static final Decimal18f HUNDREDTH = new Decimal18f(ONE_UNSCALED / 100);
123        /** The {@code Decimal18f} constant 0.001.*/
124        public static final Decimal18f THOUSANDTH = new Decimal18f(ONE_UNSCALED / 1000);
125        /** The {@code Decimal18f} constant 10<sup>-6</sup>.*/
126        public static final Decimal18f MILLIONTH = new Decimal18f(ONE_UNSCALED / 1000000);
127        /** The {@code Decimal18f} constant 10<sup>-9</sup>.*/
128        public static final Decimal18f BILLIONTH = new Decimal18f(ONE_UNSCALED / 1000000000);
129        /** The {@code Decimal18f} constant 10<sup>-12</sup>.*/
130        public static final Decimal18f TRILLIONTH = new Decimal18f(ONE_UNSCALED / 1000000000000L);
131        /** The {@code Decimal18f} constant 10<sup>-15</sup>.*/
132        public static final Decimal18f QUADRILLIONTH = new Decimal18f(ONE_UNSCALED / 1000000000000000L);
133        /** The {@code Decimal18f} constant 10<sup>-18</sup>.*/
134        public static final Decimal18f QUINTILLIONTH = new Decimal18f(ONE_UNSCALED / 1000000000000000000L);
135
136    /**
137     * A constant holding the maximum value a {@code Decimal18f} can have,
138     * 9.223372036854775807.
139     */
140        public static final Decimal18f MAX_VALUE = new Decimal18f(Long.MAX_VALUE);
141    /**
142     * A constant holding the maximum integer value a {@code Decimal18f}
143     * can have, 9.000000000000000000.
144     */
145        public static final Decimal18f MAX_INTEGER_VALUE = new Decimal18f((Long.MAX_VALUE / ONE_UNSCALED) * ONE_UNSCALED);
146    /**
147     * A constant holding the minimum value a {@code Decimal18f} can have,
148     * -9.223372036854775808.
149     */
150        public static final Decimal18f MIN_VALUE = new Decimal18f(Long.MIN_VALUE);
151    /**
152     * A constant holding the minimum integer value a {@code Decimal18f}
153     * can have, -9.000000000000000000.
154     */
155        public static final Decimal18f MIN_INTEGER_VALUE = new Decimal18f((Long.MIN_VALUE / ONE_UNSCALED) * ONE_UNSCALED);
156
157        /**
158         * Private constructor with unscaled value.
159         *
160         * @param unscaled the unscaled value
161         */
162        private Decimal18f(long unscaled) {
163                super(unscaled);
164        }
165
166        /**
167         * Translates the string representation of a {@code Decimal} into a
168         * {@code Decimal18f}. The string representation consists of an
169         * optional sign, {@code '+'} or {@code '-'} , followed by a sequence of
170         * zero or more decimal digits ("the integer"), optionally followed by a
171         * fraction.
172         * <p>
173         * The fraction consists of a decimal point followed by zero or more decimal
174         * digits. The string must contain at least one digit in either the integer
175         * or the fraction. If the fraction contains more than 18 digits, the 
176         * value is rounded using {@link RoundingMode#HALF_UP HALF_UP} rounding. An 
177         * exception is thrown if the value is too large to be represented as a 
178         * {@code Decimal18f}.
179         *
180         * @param value
181         *            String value to convert into a {@code Decimal18f}
182         * @throws NumberFormatException
183         *             if {@code value} does not represent a valid {@code Decimal}
184         *             or if the value is too large to be represented as a 
185         *             {@code Decimal18f}
186         */
187        public Decimal18f(String value) {
188                super(DEFAULT_CHECKED_ARITHMETIC.parse(value));
189        }
190        
191        @Override
192        public final Scale18f getScaleMetrics() {
193                return METRICS;
194        }
195
196        @Override
197        public final int getScale() {
198                return SCALE;
199        }
200
201        @Override
202        public final Factory18f getFactory() {
203                return FACTORY;
204        }
205
206        @Override
207        protected final Decimal18f self() {
208                return this;
209        }
210
211        @Override
212        protected final DecimalArithmetic getDefaultArithmetic() {
213                return DEFAULT_ARITHMETIC;
214        }
215        
216        @Override
217        protected final DecimalArithmetic getDefaultCheckedArithmetic() {
218                return DEFAULT_CHECKED_ARITHMETIC;
219        }
220        
221        @Override
222        protected final DecimalArithmetic getRoundingDownArithmetic() {
223                return METRICS.getRoundingDownArithmetic();
224        }
225        
226        @Override
227        protected final DecimalArithmetic getRoundingFloorArithmetic() {
228                return METRICS.getRoundingFloorArithmetic();
229        }
230        
231        @Override
232        protected final DecimalArithmetic getRoundingHalfEvenArithmetic() {
233                return METRICS.getRoundingHalfEvenArithmetic();
234        }
235        
236        @Override
237        protected final DecimalArithmetic getRoundingUnnecessaryArithmetic() {
238                return METRICS.getRoundingUnnecessaryArithmetic();
239        }
240
241        /**
242         * Returns a {@code Decimal18f} whose value is numerically equal to
243         * that of the specified {@code long} value. An exception is thrown if the
244         * specified value is too large to be represented as a {@code Decimal18f}.
245         *
246         * @param value
247         *            long value to convert into a {@code Decimal18f}
248         * @return a {@code Decimal18f} value numerically equal to the specified 
249         *            {@code long} value
250         * @throws IllegalArgumentException
251         *            if {@code value} is too large to be represented as a 
252         *            {@code Decimal18f}
253         */
254        public static Decimal18f valueOf(long value) {
255        if (value == 0)
256            return ZERO;
257        if (value > 0 & value <= MAX_CONSTANT)
258            return POS_CONST[(int) value];
259        else if (value < 0 & value >= -MAX_CONSTANT)
260            return NEG_CONST[(int) -value];
261                return valueOfUnscaled(DEFAULT_CHECKED_ARITHMETIC.fromLong(value));
262        }
263
264        /**
265         * Returns a {@code Decimal18f} whose value is calculated by
266         * rounding the specified {@code float} argument to scale 18
267         * using {@link RoundingMode#HALF_UP HALF_UP} rounding. An exception is thrown
268         * if the specified value is too large to be represented as a {@code Decimal18f}. 
269         *
270         * @param value
271         *            float value to convert into a {@code Decimal18f}
272         * @return a {@code Decimal18f} calculated as: <code>round<sub>HALF_UP</sub>(value)</code>
273         * @throws IllegalArgumentException
274         *             if {@code value} is NaN or infinite or if the magnitude is
275         *             too large for the float to be represented as a {@code Decimal18f}
276         */
277        public static Decimal18f valueOf(float value) {
278                return valueOfUnscaled(DEFAULT_CHECKED_ARITHMETIC.fromFloat(value));
279        }
280
281        /**
282         * Returns a {@code Decimal18f} whose value is calculated by
283         * rounding the specified {@code float} argument to scale 18
284         * using the specified {@code roundingMode}. An exception is thrown
285         * if the specified value is too large to be represented as a {@code Decimal18f}. 
286         *
287         * @param value
288         *            float value to convert into a {@code Decimal18f}
289         * @param roundingMode
290         *            the rounding mode to apply during the conversion if necessary
291         * @return a {@code Decimal18f} calculated as: <code>round(value)</code>
292         * @throws IllegalArgumentException
293         *             if {@code value} is NaN or infinite or if the magnitude is
294         *             too large for the float to be represented as a {@code Decimal18f}
295         * @throws ArithmeticException
296         *             if {@code roundingMode==UNNECESSARY} and rounding is
297         *             necessary
298         */
299        public static Decimal18f valueOf(float value, RoundingMode roundingMode) {
300                return valueOfUnscaled(METRICS.getCheckedArithmetic(roundingMode).fromFloat(value));
301        }
302
303        /**
304         * Returns a {@code Decimal18f} whose value is calculated by
305         * rounding the specified {@code double} argument to scale 18
306         * using {@link RoundingMode#HALF_UP HALF_UP} rounding. An exception is thrown
307         * if the specified value is too large to be represented as a {@code Decimal18f}. 
308         *
309         * @param value
310         *            double value to convert into a {@code Decimal18f}
311         * @return a {@code Decimal18f} calculated as: <code>round<sub>HALF_UP</sub>(value)</code>
312         * @throws IllegalArgumentException
313         *             if {@code value} is NaN or infinite or if the magnitude is
314         *             too large for the double to be represented as a {@code Decimal18f}
315         */
316        public static Decimal18f valueOf(double value) {
317                return valueOfUnscaled(DEFAULT_CHECKED_ARITHMETIC.fromDouble(value));
318        }
319
320        /**
321         * Returns a {@code Decimal18f} whose value is calculated by
322         * rounding the specified {@code double} argument to scale 18
323         * using the specified {@code roundingMode}. An exception is thrown
324         * if the specified value is too large to be represented as a {@code Decimal18f}. 
325         *
326         * @param value
327         *            double value to convert into a {@code Decimal18f}
328         * @param roundingMode
329         *            the rounding mode to apply during the conversion if necessary
330         * @return a {@code Decimal18f} calculated as: <code>round(value)</code>
331         * @throws IllegalArgumentException
332         *             if {@code value} is NaN or infinite or if the magnitude is
333         *             too large for the double to be represented as a {@code Decimal18f}
334         * @throws ArithmeticException
335         *             if {@code roundingMode==UNNECESSARY} and rounding is
336         *             necessary
337         */
338        public static Decimal18f valueOf(double value, RoundingMode roundingMode) {
339                return valueOfUnscaled(METRICS.getCheckedArithmetic(roundingMode).fromDouble(value));
340        }
341
342        /**
343         * Returns a {@code Decimal18f} whose value is numerically equal to that of
344         * the specified {@link BigInteger} value. An exception is thrown if the
345         * specified value is too large to be represented as a {@code Decimal18f}.
346         *
347         * @param value
348         *            {@code BigInteger} value to convert into a {@code Decimal18f}
349         * @return a {@code Decimal18f} value numerically equal to the specified big 
350         *         integer value
351         * @throws IllegalArgumentException
352         *             if {@code value} is too large to be represented as a {@code Decimal18f}
353         */
354        public static Decimal18f valueOf(BigInteger value) {
355                return valueOfUnscaled(DEFAULT_CHECKED_ARITHMETIC.fromBigInteger(value));
356        }
357
358        /**
359         * Returns a {@code Decimal18f} whose value is calculated by rounding
360         * the specified {@link BigDecimal} argument to scale 18 using
361         * {@link RoundingMode#HALF_UP HALF_UP} rounding. An exception is thrown if the 
362         * specified value is too large to be represented as a {@code Decimal18f}.
363         *
364         * @param value
365         *            {@code BigDecimal} value to convert into a {@code Decimal18f}
366         * @return a {@code Decimal18f} calculated as: <code>round<sub>HALF_UP</sub>(value)</code>
367         * @throws IllegalArgumentException
368         *             if {@code value} is too large to be represented as a {@code Decimal18f}
369         */
370        public static Decimal18f valueOf(BigDecimal value) {
371                return valueOfUnscaled(DEFAULT_CHECKED_ARITHMETIC.fromBigDecimal(value));
372        }
373
374        /**
375         * Returns a {@code Decimal18f} whose value is calculated by rounding
376         * the specified {@link BigDecimal} argument to scale 18 using 
377         * the specified {@code roundingMode}. An exception is thrown if the 
378         * specified value is too large to be represented as a {@code Decimal18f}.
379         *
380         * @param value
381         *            {@code BigDecimal} value to convert into a {@code Decimal18f}
382         * @param roundingMode
383         *            the rounding mode to apply during the conversion if necessary
384         * @return a {@code Decimal18f} calculated as: <code>round(value)</code>
385         * @throws IllegalArgumentException
386         *             if {@code value} is too large to be represented as a {@code Decimal18f}
387         * @throws ArithmeticException
388         *             if {@code roundingMode==UNNECESSARY} and rounding is
389         *             necessary
390         */
391        public static Decimal18f valueOf(BigDecimal value, RoundingMode roundingMode) {
392                return valueOfUnscaled(METRICS.getCheckedArithmetic(roundingMode).fromBigDecimal(value));
393        }
394
395        /**
396         * Returns a {@code Decimal18f} whose value is calculated by rounding
397         * the specified {@link Decimal} argument to scale 18 using
398         * {@link RoundingMode#HALF_UP HALF_UP} rounding. An exception is thrown if the
399         * specified value is too large to be represented as a {@code Decimal18f}. 
400         *
401         * @param value
402         *            Decimal value to convert into a {@code Decimal18f} 
403         * @return a {@code Decimal18f} calculated as: <code>round<sub>HALF_UP</sub>(value)</code>
404         * @throws IllegalArgumentException
405         *             if {@code value} is too large to be represented as a {@code Decimal18f}
406         */
407        public static Decimal18f valueOf(Decimal<?> value) {
408                if (value instanceof Decimal18f) {
409                        return (Decimal18f)value;
410                }
411                return valueOfUnscaled(value.unscaledValue(), value.getScale());
412        }
413
414        /**
415         * Returns a {@code Decimal18f} whose value is calculated by rounding
416         * the specified {@link Decimal} argument to scale 18 using
417         * the specified {@code roundingMode}. An exception is thrown if the
418         * specified value is too large to be represented as a {@code Decimal18f}. 
419         *
420         * @param value
421         *            Decimal value to convert into a {@code Decimal18f} 
422         * @param roundingMode
423         *            the rounding mode to apply during the conversion if necessary
424         * @return a {@code Decimal18f} calculated as: <code>round(value)</code>
425         * @throws IllegalArgumentException
426         *             if {@code value} is too large to be represented as a {@code Decimal18f}
427         * @throws ArithmeticException
428         *             if {@code roundingMode==UNNECESSARY} and rounding is
429         *             necessary
430         */
431        public static Decimal18f valueOf(Decimal<?> value, RoundingMode roundingMode) {
432                if (value instanceof Decimal18f) {
433                        return (Decimal18f)value;
434                }
435                return valueOfUnscaled(value.unscaledValue(), value.getScale(), roundingMode);
436        }
437
438        /**
439         * Translates the string representation of a {@code Decimal} into a
440         * {@code Decimal18f}. The string representation consists of an
441         * optional sign, {@code '+'} or {@code '-'} , followed by a sequence of
442         * zero or more decimal digits ("the integer"), optionally followed by a
443         * fraction.
444         * <p>
445         * The fraction consists of a decimal point followed by zero or more decimal
446         * digits. The string must contain at least one digit in either the integer
447         * or the fraction. If the fraction contains more than 18 digits, the 
448         * value is rounded using {@link RoundingMode#HALF_UP HALF_UP} rounding. An 
449         * exception is thrown if the value is too large to be represented as a 
450         * {@code Decimal18f}.
451         *
452         * @param value
453         *            String value to convert into a {@code Decimal18f}
454         * @return a {@code Decimal18f} calculated as: <code>round<sub>HALF_UP</sub>(value)</code>
455         * @throws NumberFormatException
456         *             if {@code value} does not represent a valid {@code Decimal}
457         *             or if the value is too large to be represented as a 
458         *             {@code Decimal18f}
459         */
460        public static Decimal18f valueOf(String value) {
461                return valueOfUnscaled(DEFAULT_CHECKED_ARITHMETIC.parse(value));
462        }
463
464        /**
465         * Translates the string representation of a {@code Decimal} into a
466         * {@code Decimal18f}. The string representation consists of an
467         * optional sign, {@code '+'} or {@code '-'} , followed by a sequence of
468         * zero or more decimal digits ("the integer"), optionally followed by a
469         * fraction.
470         * <p>
471         * The fraction consists of a decimal point followed by zero or more decimal
472         * digits. The string must contain at least one digit in either the integer
473         * or the fraction. If the fraction contains more than 18 digits, the 
474         * value is rounded using the specified {@code roundingMode}. An exception 
475         * is thrown if the value is too large to be represented as a {@code Decimal18f}.
476         *
477         * @param value
478         *            String value to convert into a {@code Decimal18f}
479         * @param roundingMode
480         *            the rounding mode to apply if the fraction contains more than
481         *            18 digits
482         * @return a {@code Decimal18f} calculated as: <code>round(value)</code>
483         * @throws NumberFormatException
484         *             if {@code value} does not represent a valid {@code Decimal}
485         *             or if the value is too large to be represented as a 
486         *             {@code Decimal18f}
487         * @throws ArithmeticException
488         *             if {@code roundingMode==UNNECESSARY} and rounding is
489         *             necessary
490         */
491        public static Decimal18f valueOf(String value, RoundingMode roundingMode) {
492                return valueOfUnscaled(METRICS.getCheckedArithmetic(roundingMode).parse(value));
493        }
494
495        /**
496         * Returns a {@code Decimal18f} whose value is numerically equal to
497         * <code>(unscaledValue &times; 10<sup>-18</sup>)</code>.
498         *
499         * @param unscaledValue
500         *            unscaled value to convert into a {@code Decimal18f}
501         * @return a {@code Decimal18f} calculated as:
502         *         <code>unscaledValue &times; 10<sup>-18</sup></code>
503         */
504        public static Decimal18f valueOfUnscaled(long unscaledValue) {
505                if (unscaledValue == 0) {
506                        return ZERO;
507                }
508                if (unscaledValue == 1) {
509                        return ULP;
510                }
511                if (unscaledValue == ONE_UNSCALED) {
512                        return ONE;
513                }
514                if (unscaledValue == -ONE_UNSCALED) {
515                        return MINUS_ONE;
516                }
517                return new Decimal18f(unscaledValue);
518        }
519
520        /**
521         * Returns a {@code Decimal18f} whose value is numerically equal to
522         * <code>(unscaledValue &times; 10<sup>-scale</sup>)</code>. The result is
523         * rounded to scale 18 using {@link RoundingMode#HALF_UP HALF_UP} 
524         * rounding. An exception is thrown if the specified value is too large 
525         * to be represented as a {@code Decimal18f}.
526         *
527         * @param unscaledValue
528         *            unscaled value to convert into a {@code Decimal18f}
529         * @param scale
530         *            the scale to apply to {@code unscaledValue}
531         * @return a {@code Decimal18f} calculated as:
532         *         <code>round<sub>HALF_UP</sub>(unscaledValue &times; 10<sup>-scale</sup>)</code>
533         * @throws IllegalArgumentException
534         *             if the specified value is too large to be represented as a 
535         *             {@code Decimal18f}
536         */
537        public static Decimal18f valueOfUnscaled(long unscaledValue, int scale) {
538                return valueOfUnscaled(DEFAULT_CHECKED_ARITHMETIC.fromUnscaled(unscaledValue, scale));
539        }
540
541        /**
542         * Returns a {@code Decimal18f} whose value is numerically equal to
543         * <code>(unscaledValue &times; 10<sup>-scale</sup>)</code>. The result
544         * is rounded to scale 18 using the specified {@code roundingMode}. 
545         * An exception is thrown if the specified value is too large to be 
546         * represented as a {@code Decimal18f}.
547         *
548         * @param unscaledValue
549         *            unscaled value to convert into a Decimal18
550         * @param scale
551         *            the scale to apply to {@code unscaledValue}
552         * @param roundingMode
553         *            the rounding mode to apply during the conversion if necessary
554         * @return a {@code Decimal18f} calculated as:
555         *         <code>round(unscaledValue &times; 10<sup>-scale</sup>)</code>
556         * @throws IllegalArgumentException
557         *             if the specified value is too large to be represented as a {@code Decimal18f}
558         */
559        public static Decimal18f valueOfUnscaled(long unscaledValue, int scale, RoundingMode roundingMode) {
560                return valueOfUnscaled(METRICS.getCheckedArithmetic(roundingMode).fromUnscaled(unscaledValue, scale));
561        }
562
563        @Override
564        protected Decimal18f createOrAssign(long unscaled) {
565                return valueOfUnscaled(unscaled);
566        }
567        
568        @Override
569        protected Decimal18f create(long unscaled) {
570                return valueOfUnscaled(unscaled);
571        }
572        
573        @Override
574        protected Decimal18f[] createArray(int length) {
575                return new Decimal18f[length];
576        }
577        
578        /**
579         * Returns this {@code Decimal} as a multipliable factor for typed 
580         * exact multiplication. The second factor is passed to one of the
581         * {@code by(..)} methods of the returned multiplier. The scale of
582         * the result is the sum of the scales of {@code this} Decimal and the
583         * second factor passed to the {@code by(..)} method.
584         * <p>
585         * The method is similar to {@link #multiplyExact(Decimal) multiplyExact(Decimal)} but the result
586         * is retrieved in exact typed form with the correct result scale. 
587         * <p>
588         * For instance one can write:
589         * <pre>
590         * Decimal18f product = this.multiplyExact().by(Decimal0f.FIVE);
591         * </pre>
592         * 
593         * @return a multipliable object encapsulating this Decimal as first factor
594         *             of an exact multiplication
595         */
596        public Multipliable18f multiplyExact() {
597                return new Multipliable18f(this);
598        }
599
600        @Override
601        public MutableDecimal18f toMutableDecimal() {
602                return new MutableDecimal18f(this);
603        }
604
605        @Override
606        public Decimal18f toImmutableDecimal() {
607                return this;
608        }
609}
610