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.Multipliable5f;
034import org.decimal4j.factory.Factory5f;
035import org.decimal4j.mutable.MutableDecimal5f;
036import org.decimal4j.scale.Scale5f;
037
038/**
039 * <code>Decimal5f</code> represents an immutable decimal number with a fixed
040 * number of 5 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 Decimal5f extends AbstractImmutableDecimal<Scale5f, Decimal5f> {
046
047        private static final long serialVersionUID = 1L;
048
049        /** Scale value 5 for {@code Decimal5f} returned by {@link #getScale()}.*/
050        public static final int SCALE = 5;
051
052        /** Scale metrics constant for {@code Decimal5f} returned by {@link #getScaleMetrics()}.*/
053        public static final Scale5f METRICS = Scale5f.INSTANCE;
054
055        /** Factory constant for {@code Decimal5f} returned by {@link #getFactory()}.*/
056        public static final Factory5f FACTORY = Factory5f.INSTANCE;
057        
058        /**
059         * Default arithmetic for {@code Decimal5f} 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 Decimal5f} 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 Decimal5f} constant zero.*/
074        public static final Decimal5f ZERO = new Decimal5f(0);
075    /**
076     * A constant holding the smallest positive value a {@code Decimal5f}
077     * can have, 10<sup>-5</sup>.
078     */
079        public static final Decimal5f ULP = new Decimal5f(1);
080
081    /**
082     * Initialize static constant array when class is loaded.
083     */
084    private static final int MAX_CONSTANT = 10;
085    private static final Decimal5f POS_CONST[] = new Decimal5f[MAX_CONSTANT+1];
086    private static final Decimal5f NEG_CONST[] = new Decimal5f[MAX_CONSTANT+1];
087
088    static {
089        for (int i = 1; i <= MAX_CONSTANT; i++) {
090            POS_CONST[i] = new Decimal5f(ONE_UNSCALED * i);
091            NEG_CONST[i] = new Decimal5f(-ONE_UNSCALED * i);
092        }
093    }
094
095        /** The {@code Decimal5f} constant 1.*/
096        public static final Decimal5f ONE = valueOf(1);
097        /** The {@code Decimal5f} constant 2.*/
098        public static final Decimal5f TWO = valueOf(2);
099        /** The {@code Decimal5f} constant 3.*/
100        public static final Decimal5f THREE = valueOf(3);
101        /** The {@code Decimal5f} constant 4.*/
102        public static final Decimal5f FOUR = valueOf(4);
103        /** The {@code Decimal5f} constant 5.*/
104        public static final Decimal5f FIVE = valueOf(5);
105        /** The {@code Decimal5f} constant 6.*/
106        public static final Decimal5f SIX = valueOf(6);
107        /** The {@code Decimal5f} constant 7.*/
108        public static final Decimal5f SEVEN = valueOf(7);
109        /** The {@code Decimal5f} constant 8.*/
110        public static final Decimal5f EIGHT = valueOf(8);
111        /** The {@code Decimal5f} constant 9.*/
112        public static final Decimal5f NINE = valueOf(9);
113        /** The {@code Decimal5f} constant 10.*/
114        public static final Decimal5f TEN = valueOf(10);
115        /** The {@code Decimal5f} constant 100.*/
116        public static final Decimal5f HUNDRED = new Decimal5f(100 * ONE_UNSCALED);
117        /** The {@code Decimal5f} constant 1000.*/
118        public static final Decimal5f THOUSAND = new Decimal5f(1000 * ONE_UNSCALED);
119        /** The {@code Decimal5f} constant 10<sup>6</sup>.*/
120        public static final Decimal5f MILLION = new Decimal5f(1000000 * ONE_UNSCALED);
121        /** The {@code Decimal5f} constant 10<sup>9</sup>.*/
122        public static final Decimal5f BILLION = new Decimal5f(1000000000 * ONE_UNSCALED);
123        /** The {@code Decimal5f} constant 10<sup>12</sup>.*/
124        public static final Decimal5f TRILLION = new Decimal5f(1000000000000L * ONE_UNSCALED);
125
126        /** The {@code Decimal5f} constant -1.*/
127        public static final Decimal5f MINUS_ONE = valueOf(-1);
128
129        /** The {@code Decimal5f} constant 0.5.*/
130        public static final Decimal5f HALF = new Decimal5f(ONE_UNSCALED / 2);
131        /** The {@code Decimal5f} constant 0.1.*/
132        public static final Decimal5f TENTH = new Decimal5f(ONE_UNSCALED / 10);
133        /** The {@code Decimal5f} constant 0.01.*/
134        public static final Decimal5f HUNDREDTH = new Decimal5f(ONE_UNSCALED / 100);
135        /** The {@code Decimal5f} constant 0.001.*/
136        public static final Decimal5f THOUSANDTH = new Decimal5f(ONE_UNSCALED / 1000);
137
138    /**
139     * A constant holding the maximum value a {@code Decimal5f} can have,
140     * 92233720368547.75807.
141     */
142        public static final Decimal5f MAX_VALUE = new Decimal5f(Long.MAX_VALUE);
143    /**
144     * A constant holding the maximum integer value a {@code Decimal5f}
145     * can have, 92233720368547.00000.
146     */
147        public static final Decimal5f MAX_INTEGER_VALUE = new Decimal5f((Long.MAX_VALUE / ONE_UNSCALED) * ONE_UNSCALED);
148    /**
149     * A constant holding the minimum value a {@code Decimal5f} can have,
150     * -92233720368547.75808.
151     */
152        public static final Decimal5f MIN_VALUE = new Decimal5f(Long.MIN_VALUE);
153    /**
154     * A constant holding the minimum integer value a {@code Decimal5f}
155     * can have, -92233720368547.00000.
156     */
157        public static final Decimal5f MIN_INTEGER_VALUE = new Decimal5f((Long.MIN_VALUE / ONE_UNSCALED) * ONE_UNSCALED);
158
159        /**
160         * Private constructor with unscaled value.
161         *
162         * @param unscaled the unscaled value
163         */
164        private Decimal5f(long unscaled) {
165                super(unscaled);
166        }
167
168        /**
169         * Translates the string representation of a {@code Decimal} into a
170         * {@code Decimal5f}. The string representation consists of an
171         * optional sign, {@code '+'} or {@code '-'} , followed by a sequence of
172         * zero or more decimal digits ("the integer"), optionally followed by a
173         * fraction.
174         * <p>
175         * The fraction consists of a decimal point followed by zero or more decimal
176         * digits. The string must contain at least one digit in either the integer
177         * or the fraction. If the fraction contains more than 5 digits, the 
178         * value is rounded using {@link RoundingMode#HALF_UP HALF_UP} rounding. An 
179         * exception is thrown if the value is too large to be represented as a 
180         * {@code Decimal5f}.
181         *
182         * @param value
183         *            String value to convert into a {@code Decimal5f}
184         * @throws NumberFormatException
185         *             if {@code value} does not represent a valid {@code Decimal}
186         *             or if the value is too large to be represented as a 
187         *             {@code Decimal5f}
188         */
189        public Decimal5f(String value) {
190                super(DEFAULT_CHECKED_ARITHMETIC.parse(value));
191        }
192        
193        @Override
194        public final Scale5f getScaleMetrics() {
195                return METRICS;
196        }
197
198        @Override
199        public final int getScale() {
200                return SCALE;
201        }
202
203        @Override
204        public final Factory5f getFactory() {
205                return FACTORY;
206        }
207
208        @Override
209        protected final Decimal5f self() {
210                return this;
211        }
212
213        @Override
214        protected final DecimalArithmetic getDefaultArithmetic() {
215                return DEFAULT_ARITHMETIC;
216        }
217        
218        @Override
219        protected final DecimalArithmetic getDefaultCheckedArithmetic() {
220                return DEFAULT_CHECKED_ARITHMETIC;
221        }
222        
223        @Override
224        protected final DecimalArithmetic getRoundingDownArithmetic() {
225                return METRICS.getRoundingDownArithmetic();
226        }
227        
228        @Override
229        protected final DecimalArithmetic getRoundingFloorArithmetic() {
230                return METRICS.getRoundingFloorArithmetic();
231        }
232        
233        @Override
234        protected final DecimalArithmetic getRoundingHalfEvenArithmetic() {
235                return METRICS.getRoundingHalfEvenArithmetic();
236        }
237        
238        @Override
239        protected final DecimalArithmetic getRoundingUnnecessaryArithmetic() {
240                return METRICS.getRoundingUnnecessaryArithmetic();
241        }
242
243        /**
244         * Returns a {@code Decimal5f} whose value is numerically equal to
245         * that of the specified {@code long} value. An exception is thrown if the
246         * specified value is too large to be represented as a {@code Decimal5f}.
247         *
248         * @param value
249         *            long value to convert into a {@code Decimal5f}
250         * @return a {@code Decimal5f} value numerically equal to the specified 
251         *            {@code long} value
252         * @throws IllegalArgumentException
253         *            if {@code value} is too large to be represented as a 
254         *            {@code Decimal5f}
255         */
256        public static Decimal5f valueOf(long value) {
257        if (value == 0)
258            return ZERO;
259        if (value > 0 & value <= MAX_CONSTANT)
260            return POS_CONST[(int) value];
261        else if (value < 0 & value >= -MAX_CONSTANT)
262            return NEG_CONST[(int) -value];
263                return valueOfUnscaled(DEFAULT_CHECKED_ARITHMETIC.fromLong(value));
264        }
265
266        /**
267         * Returns a {@code Decimal5f} whose value is calculated by
268         * rounding the specified {@code float} argument to scale 5
269         * using {@link RoundingMode#HALF_UP HALF_UP} rounding. An exception is thrown
270         * if the specified value is too large to be represented as a {@code Decimal5f}. 
271         *
272         * @param value
273         *            float value to convert into a {@code Decimal5f}
274         * @return a {@code Decimal5f} calculated as: <code>round<sub>HALF_UP</sub>(value)</code>
275         * @throws IllegalArgumentException
276         *             if {@code value} is NaN or infinite or if the magnitude is
277         *             too large for the float to be represented as a {@code Decimal5f}
278         */
279        public static Decimal5f valueOf(float value) {
280                return valueOfUnscaled(DEFAULT_CHECKED_ARITHMETIC.fromFloat(value));
281        }
282
283        /**
284         * Returns a {@code Decimal5f} whose value is calculated by
285         * rounding the specified {@code float} argument to scale 5
286         * using the specified {@code roundingMode}. An exception is thrown
287         * if the specified value is too large to be represented as a {@code Decimal5f}. 
288         *
289         * @param value
290         *            float value to convert into a {@code Decimal5f}
291         * @param roundingMode
292         *            the rounding mode to apply during the conversion if necessary
293         * @return a {@code Decimal5f} calculated as: <code>round(value)</code>
294         * @throws IllegalArgumentException
295         *             if {@code value} is NaN or infinite or if the magnitude is
296         *             too large for the float to be represented as a {@code Decimal5f}
297         * @throws ArithmeticException
298         *             if {@code roundingMode==UNNECESSARY} and rounding is
299         *             necessary
300         */
301        public static Decimal5f valueOf(float value, RoundingMode roundingMode) {
302                return valueOfUnscaled(METRICS.getCheckedArithmetic(roundingMode).fromFloat(value));
303        }
304
305        /**
306         * Returns a {@code Decimal5f} whose value is calculated by
307         * rounding the specified {@code double} argument to scale 5
308         * using {@link RoundingMode#HALF_UP HALF_UP} rounding. An exception is thrown
309         * if the specified value is too large to be represented as a {@code Decimal5f}. 
310         *
311         * @param value
312         *            double value to convert into a {@code Decimal5f}
313         * @return a {@code Decimal5f} calculated as: <code>round<sub>HALF_UP</sub>(value)</code>
314         * @throws IllegalArgumentException
315         *             if {@code value} is NaN or infinite or if the magnitude is
316         *             too large for the double to be represented as a {@code Decimal5f}
317         */
318        public static Decimal5f valueOf(double value) {
319                return valueOfUnscaled(DEFAULT_CHECKED_ARITHMETIC.fromDouble(value));
320        }
321
322        /**
323         * Returns a {@code Decimal5f} whose value is calculated by
324         * rounding the specified {@code double} argument to scale 5
325         * using the specified {@code roundingMode}. An exception is thrown
326         * if the specified value is too large to be represented as a {@code Decimal5f}. 
327         *
328         * @param value
329         *            double value to convert into a {@code Decimal5f}
330         * @param roundingMode
331         *            the rounding mode to apply during the conversion if necessary
332         * @return a {@code Decimal5f} calculated as: <code>round(value)</code>
333         * @throws IllegalArgumentException
334         *             if {@code value} is NaN or infinite or if the magnitude is
335         *             too large for the double to be represented as a {@code Decimal5f}
336         * @throws ArithmeticException
337         *             if {@code roundingMode==UNNECESSARY} and rounding is
338         *             necessary
339         */
340        public static Decimal5f valueOf(double value, RoundingMode roundingMode) {
341                return valueOfUnscaled(METRICS.getCheckedArithmetic(roundingMode).fromDouble(value));
342        }
343
344        /**
345         * Returns a {@code Decimal5f} whose value is numerically equal to that of
346         * the specified {@link BigInteger} value. An exception is thrown if the
347         * specified value is too large to be represented as a {@code Decimal5f}.
348         *
349         * @param value
350         *            {@code BigInteger} value to convert into a {@code Decimal5f}
351         * @return a {@code Decimal5f} value numerically equal to the specified big 
352         *         integer value
353         * @throws IllegalArgumentException
354         *             if {@code value} is too large to be represented as a {@code Decimal5f}
355         */
356        public static Decimal5f valueOf(BigInteger value) {
357                return valueOfUnscaled(DEFAULT_CHECKED_ARITHMETIC.fromBigInteger(value));
358        }
359
360        /**
361         * Returns a {@code Decimal5f} whose value is calculated by rounding
362         * the specified {@link BigDecimal} argument to scale 5 using
363         * {@link RoundingMode#HALF_UP HALF_UP} rounding. An exception is thrown if the 
364         * specified value is too large to be represented as a {@code Decimal5f}.
365         *
366         * @param value
367         *            {@code BigDecimal} value to convert into a {@code Decimal5f}
368         * @return a {@code Decimal5f} calculated as: <code>round<sub>HALF_UP</sub>(value)</code>
369         * @throws IllegalArgumentException
370         *             if {@code value} is too large to be represented as a {@code Decimal5f}
371         */
372        public static Decimal5f valueOf(BigDecimal value) {
373                return valueOfUnscaled(DEFAULT_CHECKED_ARITHMETIC.fromBigDecimal(value));
374        }
375
376        /**
377         * Returns a {@code Decimal5f} whose value is calculated by rounding
378         * the specified {@link BigDecimal} argument to scale 5 using 
379         * the specified {@code roundingMode}. An exception is thrown if the 
380         * specified value is too large to be represented as a {@code Decimal5f}.
381         *
382         * @param value
383         *            {@code BigDecimal} value to convert into a {@code Decimal5f}
384         * @param roundingMode
385         *            the rounding mode to apply during the conversion if necessary
386         * @return a {@code Decimal5f} calculated as: <code>round(value)</code>
387         * @throws IllegalArgumentException
388         *             if {@code value} is too large to be represented as a {@code Decimal5f}
389         * @throws ArithmeticException
390         *             if {@code roundingMode==UNNECESSARY} and rounding is
391         *             necessary
392         */
393        public static Decimal5f valueOf(BigDecimal value, RoundingMode roundingMode) {
394                return valueOfUnscaled(METRICS.getCheckedArithmetic(roundingMode).fromBigDecimal(value));
395        }
396
397        /**
398         * Returns a {@code Decimal5f} whose value is calculated by rounding
399         * the specified {@link Decimal} argument to scale 5 using
400         * {@link RoundingMode#HALF_UP HALF_UP} rounding. An exception is thrown if the
401         * specified value is too large to be represented as a {@code Decimal5f}. 
402         *
403         * @param value
404         *            Decimal value to convert into a {@code Decimal5f} 
405         * @return a {@code Decimal5f} calculated as: <code>round<sub>HALF_UP</sub>(value)</code>
406         * @throws IllegalArgumentException
407         *             if {@code value} is too large to be represented as a {@code Decimal5f}
408         */
409        public static Decimal5f valueOf(Decimal<?> value) {
410                if (value instanceof Decimal5f) {
411                        return (Decimal5f)value;
412                }
413                return valueOfUnscaled(value.unscaledValue(), value.getScale());
414        }
415
416        /**
417         * Returns a {@code Decimal5f} whose value is calculated by rounding
418         * the specified {@link Decimal} argument to scale 5 using
419         * the specified {@code roundingMode}. An exception is thrown if the
420         * specified value is too large to be represented as a {@code Decimal5f}. 
421         *
422         * @param value
423         *            Decimal value to convert into a {@code Decimal5f} 
424         * @param roundingMode
425         *            the rounding mode to apply during the conversion if necessary
426         * @return a {@code Decimal5f} calculated as: <code>round(value)</code>
427         * @throws IllegalArgumentException
428         *             if {@code value} is too large to be represented as a {@code Decimal5f}
429         * @throws ArithmeticException
430         *             if {@code roundingMode==UNNECESSARY} and rounding is
431         *             necessary
432         */
433        public static Decimal5f valueOf(Decimal<?> value, RoundingMode roundingMode) {
434                if (value instanceof Decimal5f) {
435                        return (Decimal5f)value;
436                }
437                return valueOfUnscaled(value.unscaledValue(), value.getScale(), roundingMode);
438        }
439
440        /**
441         * Translates the string representation of a {@code Decimal} into a
442         * {@code Decimal5f}. The string representation consists of an
443         * optional sign, {@code '+'} or {@code '-'} , followed by a sequence of
444         * zero or more decimal digits ("the integer"), optionally followed by a
445         * fraction.
446         * <p>
447         * The fraction consists of a decimal point followed by zero or more decimal
448         * digits. The string must contain at least one digit in either the integer
449         * or the fraction. If the fraction contains more than 5 digits, the 
450         * value is rounded using {@link RoundingMode#HALF_UP HALF_UP} rounding. An 
451         * exception is thrown if the value is too large to be represented as a 
452         * {@code Decimal5f}.
453         *
454         * @param value
455         *            String value to convert into a {@code Decimal5f}
456         * @return a {@code Decimal5f} calculated as: <code>round<sub>HALF_UP</sub>(value)</code>
457         * @throws NumberFormatException
458         *             if {@code value} does not represent a valid {@code Decimal}
459         *             or if the value is too large to be represented as a 
460         *             {@code Decimal5f}
461         */
462        public static Decimal5f valueOf(String value) {
463                return valueOfUnscaled(DEFAULT_CHECKED_ARITHMETIC.parse(value));
464        }
465
466        /**
467         * Translates the string representation of a {@code Decimal} into a
468         * {@code Decimal5f}. The string representation consists of an
469         * optional sign, {@code '+'} or {@code '-'} , followed by a sequence of
470         * zero or more decimal digits ("the integer"), optionally followed by a
471         * fraction.
472         * <p>
473         * The fraction consists of a decimal point followed by zero or more decimal
474         * digits. The string must contain at least one digit in either the integer
475         * or the fraction. If the fraction contains more than 5 digits, the 
476         * value is rounded using the specified {@code roundingMode}. An exception 
477         * is thrown if the value is too large to be represented as a {@code Decimal5f}.
478         *
479         * @param value
480         *            String value to convert into a {@code Decimal5f}
481         * @param roundingMode
482         *            the rounding mode to apply if the fraction contains more than
483         *            5 digits
484         * @return a {@code Decimal5f} calculated as: <code>round(value)</code>
485         * @throws NumberFormatException
486         *             if {@code value} does not represent a valid {@code Decimal}
487         *             or if the value is too large to be represented as a 
488         *             {@code Decimal5f}
489         * @throws ArithmeticException
490         *             if {@code roundingMode==UNNECESSARY} and rounding is
491         *             necessary
492         */
493        public static Decimal5f valueOf(String value, RoundingMode roundingMode) {
494                return valueOfUnscaled(METRICS.getCheckedArithmetic(roundingMode).parse(value));
495        }
496
497        /**
498         * Returns a {@code Decimal5f} whose value is numerically equal to
499         * <code>(unscaledValue &times; 10<sup>-5</sup>)</code>.
500         *
501         * @param unscaledValue
502         *            unscaled value to convert into a {@code Decimal5f}
503         * @return a {@code Decimal5f} calculated as:
504         *         <code>unscaledValue &times; 10<sup>-5</sup></code>
505         */
506        public static Decimal5f valueOfUnscaled(long unscaledValue) {
507                if (unscaledValue == 0) {
508                        return ZERO;
509                }
510                if (unscaledValue == 1) {
511                        return ULP;
512                }
513                if (unscaledValue == ONE_UNSCALED) {
514                        return ONE;
515                }
516                if (unscaledValue == -ONE_UNSCALED) {
517                        return MINUS_ONE;
518                }
519                return new Decimal5f(unscaledValue);
520        }
521
522        /**
523         * Returns a {@code Decimal5f} whose value is numerically equal to
524         * <code>(unscaledValue &times; 10<sup>-scale</sup>)</code>. The result is
525         * rounded to scale 5 using {@link RoundingMode#HALF_UP HALF_UP} 
526         * rounding. An exception is thrown if the specified value is too large 
527         * to be represented as a {@code Decimal5f}.
528         *
529         * @param unscaledValue
530         *            unscaled value to convert into a {@code Decimal5f}
531         * @param scale
532         *            the scale to apply to {@code unscaledValue}
533         * @return a {@code Decimal5f} calculated as:
534         *         <code>round<sub>HALF_UP</sub>(unscaledValue &times; 10<sup>-scale</sup>)</code>
535         * @throws IllegalArgumentException
536         *             if the specified value is too large to be represented as a 
537         *             {@code Decimal5f}
538         */
539        public static Decimal5f valueOfUnscaled(long unscaledValue, int scale) {
540                return valueOfUnscaled(DEFAULT_CHECKED_ARITHMETIC.fromUnscaled(unscaledValue, scale));
541        }
542
543        /**
544         * Returns a {@code Decimal5f} whose value is numerically equal to
545         * <code>(unscaledValue &times; 10<sup>-scale</sup>)</code>. The result
546         * is rounded to scale 5 using the specified {@code roundingMode}. 
547         * An exception is thrown if the specified value is too large to be 
548         * represented as a {@code Decimal5f}.
549         *
550         * @param unscaledValue
551         *            unscaled value to convert into a Decimal5
552         * @param scale
553         *            the scale to apply to {@code unscaledValue}
554         * @param roundingMode
555         *            the rounding mode to apply during the conversion if necessary
556         * @return a {@code Decimal5f} calculated as:
557         *         <code>round(unscaledValue &times; 10<sup>-scale</sup>)</code>
558         * @throws IllegalArgumentException
559         *             if the specified value is too large to be represented as a {@code Decimal5f}
560         */
561        public static Decimal5f valueOfUnscaled(long unscaledValue, int scale, RoundingMode roundingMode) {
562                return valueOfUnscaled(METRICS.getCheckedArithmetic(roundingMode).fromUnscaled(unscaledValue, scale));
563        }
564
565        @Override
566        protected Decimal5f createOrAssign(long unscaled) {
567                return valueOfUnscaled(unscaled);
568        }
569        
570        @Override
571        protected Decimal5f create(long unscaled) {
572                return valueOfUnscaled(unscaled);
573        }
574        
575        @Override
576        protected Decimal5f[] createArray(int length) {
577                return new Decimal5f[length];
578        }
579        
580        /**
581         * Returns this {@code Decimal} as a multipliable factor for typed 
582         * exact multiplication. The second factor is passed to one of the
583         * {@code by(..)} methods of the returned multiplier. The scale of
584         * the result is the sum of the scales of {@code this} Decimal and the
585         * second factor passed to the {@code by(..)} method.
586         * <p>
587         * The method is similar to {@link #multiplyExact(Decimal) multiplyExact(Decimal)} but the result
588         * is retrieved in exact typed form with the correct result scale. 
589         * <p>
590         * For instance one can write:
591         * <pre>
592         * Decimal7f product = this.multiplyExact().by(Decimal2f.FIVE);
593         * </pre>
594         * 
595         * @return a multipliable object encapsulating this Decimal as first factor
596         *             of an exact multiplication
597         */
598        public Multipliable5f multiplyExact() {
599                return new Multipliable5f(this);
600        }
601
602        @Override
603        public MutableDecimal5f toMutableDecimal() {
604                return new MutableDecimal5f(this);
605        }
606
607        @Override
608        public Decimal5f toImmutableDecimal() {
609                return this;
610        }
611}