001/*
002 * The MIT License (MIT)
003 *
004 * Copyright (c) 2015-2023 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.arithmetic;
025
026/**
027 * Helper class to emulate unsigned 64bit operations.
028 */
029public final class Unsigned {
030
031        /**
032         * A (self-inverse) bijection which converts the ordering on unsigned longs
033         * to the ordering on longs, that is, {@code a <= b} as unsigned longs if
034         * and only if {@code flip(a) <= flip(b)} as signed longs.
035         * <p>
036         * From Guava's <a href=
037         * "http://docs.guava-libraries.googlecode.com/git/javadoc/src-html/com/google/common/primitives/UnsignedLongs.html"
038         * >UnsignedLongs</a>.
039         * 
040         * @param a the unsigned long value to flip
041         * @return the flipped value
042         */
043        private static final long flip(long a) {
044                return a ^ Long.MIN_VALUE;
045        }
046
047        /**
048         * Compares the two specified {@code long} values, treating them as unsigned
049         * values between {@code 0} and {@code 2^64 - 1} inclusive.
050         * <p>
051         * From Guava's <a href=
052         * "http://docs.guava-libraries.googlecode.com/git/javadoc/src-html/com/google/common/primitives/UnsignedLongs.html"
053         * >UnsignedLongs</a>.
054         *
055         * @param a
056         *            the first unsigned {@code long} to compare
057         * @param b
058         *            the second unsigned {@code long} to compare
059         * @return a negative value if {@code a} is less than {@code b}; a positive
060         *         value if {@code a} is greater than {@code b}; or zero if they are
061         *         equal
062         */
063        public static final int compare(long a, long b) {
064                return Long.compare(flip(a), flip(b));
065        }
066
067        /**
068         * Compare two longs as if they were unsigned. Returns true iff one is
069         * bigger than two.
070         * 
071         * @param one
072         *            the first unsigned {@code long} to compare
073         * @param two
074         *            the second unsigned {@code long} to compare
075         * @return true if {@code one > two}
076         */
077        public static final boolean isGreater(long one, long two) {
078                return flip(one) > flip(two);
079        }
080
081        /**
082         * Compare two longs as if they were unsigned. Returns true iff one is
083         * smaller than two.
084         * 
085         * @param one
086         *            the first unsigned {@code long} to compare
087         * @param two
088         *            the second unsigned {@code long} to compare
089         * @return true if {@code one < two}
090         */
091        public static final boolean isLess(long one, long two) {
092                return flip(one) < flip(two);
093        }
094
095        /**
096         * Compare two longs as if they were unsigned. Returns true iff one is less
097         * than or equal to two.
098         * 
099         * @param one
100         *            the first unsigned {@code long} to compare
101         * @param two
102         *            the second unsigned {@code long} to compare
103         * @return true if {@code one <= two}
104         */
105        public static final boolean isLessOrEqual(long one, long two) {
106                return flip(one) <= flip(two);
107        }
108
109        /**
110         * Returns dividend / divisor, where the dividend and divisor are treated as
111         * unsigned 64-bit quantities.
112         *
113         * @param dividend
114         *            the dividend (numerator)
115         * @param divisor
116         *            the divisor (denominator)
117         * @return {@code dividend / divisor}
118         * @throws ArithmeticException
119         *             if divisor is 0
120         */
121        public static final long divide(long dividend, long divisor) {
122                if (divisor < 0) { // i.e., divisor >= 2^63:
123                        return compare(dividend, divisor) < 0 ? 0 : 1;
124                }
125
126                // Optimization - use signed division if dividend < 2^63
127                if (dividend >= 0) {
128                        return dividend / divisor;
129                }
130                // If divisor is even, we can divide both by 2
131                if (0 == (divisor & 0x1)) {
132                        return (dividend >>> 1) / (divisor >>> 1);
133                }
134
135                /*
136                 * Otherwise, approximate the quotient, check, and correct if necessary.
137                 * Our approximation is guaranteed to be either exact or one less than
138                 * the correct value. This follows from fact that floor(floor(x)/i) ==
139                 * floor(x/i) for any real x and integer i != 0. The proof is not quite
140                 * trivial.
141                 */
142                long quotient = ((dividend >>> 1) / divisor) << 1;
143                long rem = dividend - quotient * divisor;
144                return quotient + (isLess(rem, divisor) ? 0 : 1);
145        }
146
147        private Unsigned() {
148                // no instances
149        }
150
151}