P
P
pqgg7nwkd42016-08-24 23:31:58
Java
pqgg7nwkd4, 2016-08-24 23:31:58

How to make muldiv for big longs in java?

Good afternoon.
It is proposed to write a function that will perform the following arithmetic operation:
V * A / B.
Requirements:
1. All values ​​are of type long, the result must be of type long.
2. If the result does not fit into a long, the function must "throw" an exception.
3. The function must return the correct value, in case V * A does not fit into long.
4. The function must have the same precision as the usual integer multiplication and division of small values.
5. The most important thing. The function must not create objects (except for exceptions), must not use floating point numbers. BigDecimal, BigInteger cannot be used. Creating arrays of scalars is discouraged.
6. Problem with an asterisk. The function must not contain loops.
The whole problem is exactly 3 and 5 points.
Example for testing:

import java.math.BigInteger;
import java.util.Objects;

public class XP {

    /**
     * Требуемая функция, для расчета value * mul / div.
     */
    public static long mulDiv (long value, long mul, long div) {
        return value * mul / div;
    }

    /**
     * Тест функции. Выводит в консоль результат и ожидаемый результат.
     */
    public static void mulDivTest (long value, long mul, long div) {
        System.out.printf("%d * %d / %d = ", value, mul, div);
        try {
            Long expected;
            try {
                expected = BigInteger.valueOf(value)
                                     .multiply(BigInteger.valueOf(mul))
                                     .divide(BigInteger.valueOf(div))
                                     .longValueExact();
            } catch (Throwable t) {
                expected = null;
            }
            Long got;
            try {
                got = mulDiv(value, mul, div);
            } catch (Throwable t) {
                got = null;
            }
            if (Objects.equals(got, expected)) {
                System.out.printf("%d  OK%n", got);
            } else {
                System.out.printf("%d  !!! FAILED, expected: %d%n", got, expected);
            }
        } catch (Throwable t) {
            System.out.println(t.getMessage());
        }
    }

    public static void main (String[] args) {
        mulDivTest(1, 2, 3);
        mulDivTest(10, 2, 3);
        mulDivTest(10, -2, 3);
        mulDivTest(10, -2, -3);
        mulDivTest(10, 2, -3);
        mulDivTest(1, 3, 3);
        mulDivTest(1, -3, 3);
        mulDivTest(1, 3, -3);
        mulDivTest(1, -3, -3);
        mulDivTest(1000_000_000_000_000_000L, 2_000_000_000L, 3_000_000_000L);
        mulDivTest(1000_000_000_000_000_000L, -2_000_000_000L, 3_000_000_000L);
        mulDivTest(1000_000_000_000_000_000L, 2_000_000_000L, -3_000_000_000L);
        mulDivTest(Long.MIN_VALUE, Long.MAX_VALUE, Long.MAX_VALUE);
        mulDivTest(Long.MAX_VALUE, Long.MAX_VALUE, Long.MIN_VALUE);
        mulDivTest(Long.MAX_VALUE, Long.MAX_VALUE, 100);

        // Задержка для IDEA, чтобы вмешивала в вывод свою информацию.
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
        }
    }
}

Example output:
1 * 2 / 3 = 0  OK
10 * 2 / 3 = 6  OK
10 * -2 / 3 = -6  OK
10 * -2 / -3 = 6  OK
10 * 2 / -3 = -6  OK
1 * 3 / 3 = 1  OK
1 * -3 / 3 = -1  OK
1 * 3 / -3 = -1  OK
1 * -3 / -3 = 1  OK
1000000000000000000 * 2000000000 / 3000000000 = 1528315472  !!! FAILED, expected: 666666666666666666
1000000000000000000 * -2000000000 / 3000000000 = -1528315472  !!! FAILED, expected: -666666666666666666
1000000000000000000 * 2000000000 / -3000000000 = -1528315472  !!! FAILED, expected: -666666666666666666
-9223372036854775808 * 9223372036854775807 / 9223372036854775807 = -1  !!! FAILED, expected: -9223372036854775808
9223372036854775807 * 9223372036854775807 / -9223372036854775808 = 0  !!! FAILED, expected: -9223372036854775806
9223372036854775807 * 9223372036854775807 / 100 = 0  !!! FAILED, expected: null

UPD:
A relatively close version was found on the Internet:
/**
     * Требуемая функция, для расчета value * mul / div.
     */
    public static long mulDiv (long a, long b, long c) {
        long whole = a / c * b;
        long fraction1 = (a % c) * (b / c);
        long fraction2 = (a % c) * (b % c) / c;
        return whole + fraction1 + fraction2;
    }

Test result:
1 * 2 / 3 = 0  OK
10 * 2 / 3 = 6  OK
10 * -2 / 3 = -6  OK
10 * -2 / -3 = 6  OK
10 * 2 / -3 = -6  OK
1 * 3 / 3 = 1  OK
1 * -3 / 3 = -1  OK
1 * 3 / -3 = -1  OK
1 * -3 / -3 = 1  OK
1000000000000000000 * 2000000000 / 3000000000 = 666666666666666666  OK
1000000000000000000 * -2000000000 / 3000000000 = -666666666666666666  OK
1000000000000000000 * 2000000000 / -3000000000 = -666666666666666666  OK
999000000000000000 * 1000000000000000000 / -1000000000000000000 = -999000000000000000  OK
-9223372036854775808 * 9223372036854775807 / 9223372036854775807 = -9223372036854775808  OK
9223372036854775807 * 9223372036854775807 / -9223372036854775808 = 0  !!! FAILED, expected: -9223372036854775806
9223372036854775807 * 9223372036854775807 / 100 = 553402322211286548  !!! FAILED, expected: null

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Alexey Cheremisin, 2016-08-25
@leahch

Well, V*A/B = (V/B)*(A/B)
I'm wrong! It's bad without a piece of paper...
=(V/B)*A or =V*(B/A)
Accordingly, we find the larger of V and A, divide it, then multiply. Well, there the remainder of the division can be taken somewhere ..

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question