수많은 도전의 맥락에서 나는 이것이 흥미로울 것이라고 생각했다.
이 과제에서, 우리는 RSN ( Residue Number System )을 사용하여 큰 정수에 더하기, 빼기 및 곱하기를 수행 할 것입니다.
RNS는 무엇입니까
RNS는 사람들이 정수를 식별하기 위해 개발 한 많은 방법 중 하나입니다. 이 시스템에서 숫자는 일련의 잔류 물로 표현됩니다 (이는 모듈러스 연산 후의 결과 (즉, 정수 나누기 후의 나머지)). 이 시스템에서 각 정수에는 많은 표현이 있습니다. 사물을 단순하게 유지하기 위해 각 정수가 고유하게 표시되도록 사물을 제한합니다. 구체적인 예에서 무슨 일이 일어나고 있는지 설명하는 것이 더 쉽다고 생각합니다.
처음 3 개의 소수 (2, 3, 5)를 살펴 보겠습니다. RNS 시스템에서이 3 개의 숫자를 사용하여 2 * 3 * 5 = 30 미만의 숫자를 고유하게 나타낼 수 있습니다. 21을 가져 가라 :
21은 30보다 작으므로 2, 3, 5로 모딩 한 후 결과를 사용하여 나타낼 수 있습니다 (즉, 정수를 2, 3, 5로 나눈 나머지)
다음 정수 시퀀스로 21을 식별합니다.
21 ~ {21 mod 2, 21 mod 3, 21 mod 5} = {1, 0, 1}
따라서 RNS 시스템에서는 "21"대신 {1,0,1}을 사용합니다.
일반적으로 정수 n이 주어지면 , 우리는 n 을 { n mod 2, ..., n mod p_k }로 나타냅니다. 여기서 p_k 는 가장 작은 소수이므로 n 은 p_k 이하의 모든 소수의 곱보다 작습니다 .
또 다른 예로, 3412가 있다고 가정합니다. 여기에서는 2,3,5,7,11,13을 사용해야 합니다. 2*3*5*7*11*13=30030
반면에 2*3*5*7*11=2310
너무 작기 때문입니다.
3412 ~ {3412 mod 2, 3412 mod 3, 3412, mod 5, ..., 3412 mod 13} = {0, 1, 2, 3, 2, 6}
이 시스템을 사용하면 상대적으로 고통없이 매우 많은 수를 나타낼 수 있습니다. {1, 2, 3, 4, 5, 6, 7, 8, ...} 잔기를 사용하여 최대 {2, 6, 30, 210, 2310, 30030, 510510, 9699690 ...}까지의 숫자를 나타낼 수 있습니다. 각기. ( 여기 시리즈입니다 )
우리의 임무
우리는 이러한 잔류 물을 사용하여 많은 수에서 +,-및 *를 수행 할 것입니다. 아래에서 이러한 프로세스를 설명하겠습니다. 지금은 입력 및 출력 사양입니다.
입력
stdin 또는 함수 인수를 통해 두 개의 (잠재적으로 큰) 숫자가 제공됩니다. 기본 10 자리 문자열로 제공됩니다.
문제를 더 설명하기 위해 첫 번째 입력 n
과 두 번째 입력을 호출합니다 m
. n> m> = 0이라고 가정하십시오 .
또한 주어집니다 +
하거나 -
또는 *
수행 할 작업을 나타냅니다.
산출
x를 정수로 하자 . 우리는 [사용하는 X 의 전술 한 RNS의 표현을 참조] X .
당신은 출력해야합니다 [n] <operator> [m] = [result]
RNS에서 작업을 수행하는 방법
이러한 작업은 비교적 간단합니다. RNS 표기법에 두 개의 숫자가 주어지면 더하거나 빼거나 곱하기 위해 주어진 연산을 구성 요소별로 수행 한 다음 모듈러스를 취하십시오.
즉
{1, 2, 3} + {1, 1, 4} = {(1 + 1) mod 2, (2 + 1) mod 3, (3 + 4) mod 5} = {0, 0, 2}
두 개의 서로 다른 숫자를 나타내는 데 사용 된 잔기 수가 동일하지 않은 경우, 작업을 수행 할 때 "더 짧은"숫자를 확장하여 동일한 수의 잔기를 갖도록해야합니다. 이것은 동일한 과정을 따릅니다. 예제는 테스트 사례를 참조하십시오.
결과에 입력보다 더 많은 잔류 물이 필요한 경우에도 마찬가지입니다. 그런 다음 두 입력을 모두 "확장"해야합니다.
중요한 세부 사항
여기서는 큰 숫자를 다루지 만 임의로 큰 것은 아닙니다. 우리는 처음 100 개의 프라임 제품의 숫자까지 책임을집니다 (아래 참조). 이를 위해 첫 100 개의 프라임이 무료로 제공됩니다 (바이트 비용 없음) . 당신은 그것들
p
을 당신의 언어에 관용적 이라고 불리는 배열에 붙인 다음 최종 배열에서이 배열을 시작하는데 사용 된 바이트 수를 뺍니다. 이것은 물론 하드 코딩되었거나 내장을 사용하여 생성 할 수 있음을 의미합니다.어떤 이유로 든 이것이 언어에서 사용되는 기본 정수 표현입니다. 괜찮습니다.
언어의 기본값이 아닌 경우 임의 정밀도 정수 유형을 사용할 수 없습니다. 기본값 인 경우 일반적으로 64 비트에 맞지 않는 정수를 저장하는 데 사용할 수 없습니다.
명확하게하기 위해, 각각의 정수는 항상 가능한 가장 적은 잔기로 표현 될 것이다. 이것은 입력과 출력 모두에 적용됩니다.
다른 사양은 이것을 방지해야하지만 중복되어야한다고 생각합니다. 입력에서 주어진 작업을 수행하지 못한 다음 모든 것을 RNS로 변경 한 다음 출력 할 수 있습니다. 입력을 RNS로 변경 한 다음 조작을 수행하여 출력을 생성해야합니다.
테스트 사례
입력:
n = 10
m = 4
+
산출:
{ 0, 1, 0 } + { 0, 1 } = { 0, 2, 4 }
설명:
먼저 위에서 설명한대로 각 번호를 RNS 표시로 변경하십시오.
10 ~ {0,1,0}
그리고 4 ~ {0,1}
. 컴포넌트 단위로 추가하고 싶을 때, 10
그보다 더 많은 컴포넌트가 4
있습니다. 따라서 더 짧은 숫자를 "확장"해야합니다. 그래서 우리는 간단히 쓸 것 4 ~ {0,1} --> {0,1, 4 mod 5} = {0,1,4}
입니다. 이제 덧셈을 진행 한 후 모듈러스를 취합니다.
- 입력
n=28
m=18
+
산출:
[ 0, 1, 3 ] + [0, 0, 3 ] = [ 0, 1, 1, 4 ]
- 입력 (키보드에서 내 얼굴을 으깨는 소리)
n=1231725471982371298419823012819231982571923
m=1288488183
*
출력 (가독성을 위해 별도의 줄에 끊김) :
[1, 2, 3, 6, 2, 10, 2, 1, 12, 16, 7, 15, 34, 29, 31, 5, 55, 32, 66, 61, 3, 76, 52, 14, 65, 44, 99, 57 ]
*
[1, 0, 3, 3, 4, 8, 9, 10, 8, 0 ]
=
[1, 0, 4, 4, 8, 2, 1, 10, 4, 0, 17, 7, 27, 21, 44, 51, 56, 9, 6, 9, 12, 0, 52, 36, 43, 68, 99, 24, 96, 39, 96, 66, 125]
n
28 프라임이 필요합니다. m
10이 n*m
필요 합니다. 33이 필요합니다.
- 입력
n=8709668761379269784034173446876636639594408083936553641753483991897255703964943107588335040121154680170867105541177741204814011615930342030904704147856733048115934632145172739949220591246493529224396454328521288726490
m=1699412683745170450115957274739962577420086093042490863793456500767137147999161679589295549397604032154933975242548831536518655879433595016
-
산출:
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 509]
-
[0, 2, 1, 6, 1, 12, 11, 18, 14, 28, 21, 36, 37, 42, 16, 52, 41, 60, 16, 70, 49, 78, 80, 88, 49, 100, 13, 106, 4, 112, 68, 130, 36, 138, 37, 150, 0, 162, 8, 172, 163, 180, 18, 192, 129, 198, 135, 222, 78, 228, 90, 238, 57, 250, 36, 262, 87, 270, 206, 280, 193, 292, 253, 310, 224, 316, 57, 336, 48, 348]
=
[0, 1, 4, 1, 10, 1, 6, 1, 9, 1, 10, 1, 4, 1, 31, 1, 18, 1, 51, 1, 24, 1, 3, 1, 48, 1, 90, 1, 105, 1, 59, 1, 101, 1, 112, 1, 0, 1, 159, 1, 16, 1, 173, 1, 68, 1, 76, 1, 149, 1, 143, 1, 184, 1, 221, 1, 182, 1, 71, 1, 90, 1, 54, 1, 89, 1, 274, 1, 299, 1, 266, 1, 228, 1, 340, 1, 170, 1, 107, 1, 340, 1, 88, 1, 157, 1, 143, 1, 22, 1, 22, 1, 58, 1, 296, 1, 371, 1, 140]
n
100 소수를 사용합니다. m
70 개의 소수를 사용합니다. n-m
99 소수를 사용합니다.
나는 ChineseRem
기본적으로 RNS 숫자를 취하고 기본 10 정수로 변경하는 GAP에 대한 기본 중국어 정리 정리 구현을 사용하여이를 확인 했습니다. 나는 그들이 옳다고 믿는다. 비린내가 있으면 알려주세요.
관심있는 사람들을 위해, 처음 100 프라임의 결과는 다음과 같습니다.
471193079990618495316248783476026042202057477340967552018863483961641533584503
422120528925670554468197243910409777715799180438028421831503871944494399049257
9030720635990538452312528339864352999310398481791730017201031090
이 수는 주어진 시스템을 사용하여 나타낼 수있는 최대 수보다 1이 큽니다 (100 개의 소수 제한).
(a,b,o)=>a.map((v,i)=>eval(v+o+b[i]))
합니다. 예를 들어 작업 수행은 ES6에 있습니다. RNS 로의 후속 변환이 정확히 사소한 것은 아니지만 가장 어려운 부분은 임의의 정밀 산술을 사용하지 않고 결과를 나타내는 데 필요한 소수를 찾는 것입니다.
1234,1234,+
)?