문제
주어진 이상한 long x
,내가 찾는 long y
이러한 그들의 제품 모듈 2**64
(즉,사용하여 넘치는 정상적인 산술)동등한 것 1.을 명확하게 무슨 뜻인:이 될 수 있는 계산에 몇 천년 이 방법:
for (long y=1; ; y+=2) {
if (x*y == 1) return y;
}
내가 알고 있는 것이 해결될 수 있을 사용하여 빠르게 확장된 유클리드 알고리즘,하지만 그것을 할 수있는 능력을 필요로 나타내는 모든 참여자(이르 2**64
, 도 산술 부호 없는 것을 도울).용 BigInteger
확실히 도움이 될 것이지만 내가 궁금해 있는 경우에는 간단한 방법으로,아마도를 사용하는 확장 유클리드 알고리즘 구현에 대한 긍정적인 갈망하고.
해결책
여기에는 방법 중 하나 그것을 하고 있다.이 사용하는 확장 유클리드 알고리즘을 찾는 역의 abs(x)
모듈 262, 고 끝에 그것은'연장'응답하는 역 modulo264 고 적용하는 기호로 변경 필요한 경우:
public static long longInverse(long x) {
if (x % 2 == 0) { throw new RuntimeException("must be odd"); }
long power = 1L << 62;
long a = Math.abs(x);
long b = power;
long sign = (x < 0) ? -1 : 1;
long c1 = 1;
long d1 = 0;
long c2 = 0;
long d2 = 1;
// Loop invariants:
// c1 * abs(x) + d1 * 2^62 = a
// c2 * abs(x) + d2 * 2^62 = b
while (b > 0) {
long q = a / b;
long r = a % b;
// r = a - qb.
long c3 = c1 - q*c2;
long d3 = d1 - q*d2;
// Now c3 * abs(x) + d3 * 2^62 = r, with 0 <= r < b.
c1 = c2;
d1 = d2;
c2 = c3;
d2 = d3;
a = b;
b = r;
}
if (a != 1) { throw new RuntimeException("gcd not 1 !"); }
// Extend from modulo 2^62 to modulo 2^64, and incorporate sign change
// if necessary.
for (int i = 0; i < 4; ++i) {
long possinv = sign * (c1 + (i * power));
if (possinv * x == 1L) { return possinv; }
}
throw new RuntimeException("failed");
}
나는 그것을 발견하고 쉽게 작업 262 263, 주로 피할 수 있기 때문에 문제가 부정 번호:263 로 Java long
은 부정적이다.
다른 팁
그 동안 나는 회수/재창조 아주 간단한 해결책:
public static int inverseOf(int x) {
Preconditions.checkArgument((x&1)!=0, "Only odd numbers have an inverse, got " + x);
int y = 1;
for (int mask=2; mask!=0; mask<<=1) {
final int product = x * y;
final int delta = product & mask;
y |= delta;
}
return y;
}
그것은 작동하기 때문에 두 가지의:
- 에서 각 반복하는 경우 해당 비트의
product
가1
,그것의 잘못,그리고 해결하는 유일한 방법은 변경하여 해당 비트의y
- no 트
y
영향이 덜 중요한 비트의product
, 다,그래서 이전 작업 취소
로 시작했는데 int
이후 long
그것은 일해야 한도,그리고 대 int
나는 실행할 수 있는 완전한 테스트입니다.
또 다른 아이디어:이 있어야 합니다 숫자 n>0
러 x**n == 1
, 며,따라서 y == x**(n-1)
.이는 아마도 더 빠르고,나는 그냥 기억이 없어요 충분한 수학 계산 n
.