На Java есть метод Евклида или полом дулю
оператор Java по модулю %
основано на усеченном делении (см. Википедия: операция по модулю).
-
5%3
производит2
(заметим, что5/3
производит1
) -
5%(-3)
производит2
(заметим, что5/(-3)
производит-1
) -
(-5)%3
производит-2
(заметим, что(-5)/3
производит-1
) -
(-5)%(-3)
производит-2
(заметим, что(-5)/(-3)
производит1
)
в вычислительной науке, учитывая два целых числа a
и n
, n
> 0, иногда полезно получить уникальное целое число r
внутри [a,n[
которая конгруэнтна a
по модулю n
.
вопрос
есть ли эффективный универсальный оператор / метод в Java, который уважает эту спецификацию по модулю?
это позволит избежать переписывания его в каждом проекте, где это необходимый...
разное
я нашел много вопросов о stackoverflow об этой проблеме, большинство из них путают различные реализации по модулю. Если вас просто беспокоят результаты операции по модулю на отрицательных числах, ниже приведены некоторые реализации на основе Java %
оператор это может быть полезно.
Common hack
поскольку мы вряд ли используем отрицательный делитель, эта реализация возвращает Евклидово или floored по модулю, когда n > 0
.
static int mod(int a, int n){
return a<0 ? (a%n + n)%n : a%n;
}
-
mod( 5, 3)
производит2
-
mod(-5, 3)
производит1
евклидовом по модулю
static int euclideanModulo(int a, int n){
return n<0 ? euclideanModulo(a, -n) : mod(a, n);
}
-
euclideanModulo( 5, 3)
производит2
-
euclideanModulo(-5, 3)
производит1
-
euclideanModulo( 5,-3)
производит2
-
euclideanModulo(-5,-3)
производит1
пол дулю
static int flooredModulo(int a, int n){
return n<0 ? -flooredModulo(-a, -n) : mod(a, n);
}
-
flooredModulo( 5, 3)
производит2
-
flooredModulo(-5, 3)
производит1
-
flooredModulo( 5,-3)
производит-1
-
flooredModulo(-5,-3)
производит-2
2 ответов
+----+----+-----------+---------+-----------+-----------+---------+-----------+ | x mod y | quotient 'q' | remainder 'r' | | x | y | truncated | floored | Euclidean | truncated | floored | Euclidean | +----+----+-----------+---------+-----------+-----------+---------+-----------+ | 5 | 3 | 1 | 1 | 1 | 2 | 2 | 2 | | -5 | 3 | -1 | -2 | -2 | -2 | 1 | 1 | | 5 | -3 | -1 | -2 | -1 | 2 | -1 | 2 | | -5 | -3 | 1 | 1 | 2 | -2 | -2 | 1 | +----+----+-----------+---------+-----------+-----------+---------+-----------+
любой из них удовлетворяет, по крайней мере,x = yq + r
.
усеченное деление и по модулю
static int truncatedDiv(int x, int y) {
return x / y;
}
static int truncatedMod(int x, int y) {
return x % y;
}
напольное деление и по модулю
вы можете использовать методы в java.lang.Math
начиная с Java 8. См.floorDiv и floorMod.
static int floorDiv(int x, int y) {
return Math.floorDiv(x, y);
}
static int floorMod(int x, int y) {
return Math.floorMod(x, y);
}
евклидово деление и по модулю
a) на основе усеченного деления
import static java.lang.Math.*;
static int euclideanDiv(int x, int y) {
int r = x / y;
// if the divident is negative and modulo not zero, round down for positive divisor, otherwise round up
if (x < 0 && r * y != x) {
r -= signum(y);
}
return r;
}
static int euclideanMod(int x, int y) {
int r = x - euclideanDiv(x, y) * y;
return r;
}
b) на основе напольного разделения
import static java.lang.Math.*;
static int euclideanDiv(int x, int y) {
int r = floorDiv(x, y);
// if the divisor is negative and modulo not zero, round up
if (y < 0 && r * y != x) {
r++;
}
return r;
}
static int euclideanMod(int x, int y) {
int r = x - euclideanDiv(x, y) * y;
return r;
}
C) на основании по абсолютному модулю
import static java.lang.Math.*;
static int euclideanMod(int x, int y) {
int r = abs(x) % abs(y);
// apply the sign of divident and make sure the remainder is positive number
r *= signum(x);
r = (r + abs(y)) % abs(y);
return r;
}
Как насчет этого кода
public static int gcd(int p, int q) {
if(count == 0)
System.out.print("Gcd for " + p + " and " + q);
if (q == 0) {
System.out.println(" returns " + p + " after " + count + " iterations");
return p;
}
count++;
return gcd(q, p % q);
}
public static void main(String[] args) {
count = 0;
gcd(4, 16);
count = 0;
gcd(4, 16);
count = 0;
gcd(16, 4);
count = 0;
gcd(15, 60);
count = 0;
gcd(15, 65);
count = 0;
gcd(1052, 52);
}