就大量挑战而言,我认为这可能很有趣。
在此挑战中,我们将使用残数系统(RNS)对大整数执行加法,减法和乘法。
什么是RNS
RNS是人们开发用于识别整数的多种方法之一。在该系统中,数字由一系列残差表示(它们是模运算后的结果(即整数除法后的余数))。在此系统中,每个整数都有许多表示形式。为了使事情简单,我们将限制事情,以便每个整数都唯一表示。我认为用一个具体的例子来描述正在发生的事情比较容易。
让我们看一下前三个质数:2、3、5。在RNS系统中,我们可以使用这三个数来唯一表示任何小于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系统中,我们将使用{1,0,1}而不是“ 21”。
通常给定整数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或function参数获得两个(可能非常大)的数字。它们将以基数为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
或您的语言习惯的数组中,然后从最终总数中减去用于启动此数组的字节数。当然,这意味着它们可能是硬编码的,或者您可以使用内置函数来生成它们。如果由于某种原因,这是您的语言中使用的默认整数表示形式。那样就好。
除非它是您的语言的默认设置,否则您不能使用任何Arbitrary Precision Integer类型。如果是默认值,则不能使用它存储通常不适合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
GAP中的中国余数定理的内置实现检查了它们(基本上采用RNS数字并将其更改为以10为基数的整数)。我相信他们是正确的。如果有些东西看起来可疑,请告诉我。
对于那些关心的人,前100个素数的乘积是:
471193079990618495316248783476026042202057477340967552018863483961641533584503
422120528925670554468197243910409777715799180438028421831503871944494399049257
9030720635990538452312528339864352999310398481791730017201031090
这个数字比使用给定系统可以表示的最大数字大1(和100个质数限制)。
(a,b,o)=>a.map((v,i)=>eval(v+o+b[i]))
例如,仅在ES6中执行该操作。我认为最困难的部分可能是在不使用任意精度算术的情况下,找到表示结果所需的素数,尽管随后转换为RNS并不是一件容易的事。
1234,1234,+
)吗?