任意精度整数部


16

我们将实现任意大整数的除法。

这是

任务是编写实现任意精度整数和除法的程序或函数。

请注意,不允许使用许多可能会很容易做到的事情,请确保通读规范

输入值

您将获得两件事作为输入:

  1. 一串以10为基数的数字,将其称为n
  2. 另一个以10为基数的字符串,称为 m

假设这n>m>0意味着您将永远不会被零除

输出量

您会输出两个数字,QR其中M * Q + R =正0 <= R <米

技术指标

  • 您的提交应适用于任意大整数(受可用内存限制)。

  • 可能不使用外部库。如果需要用于I / O的外部库,则可以将其视为内置库。(查看iostream之类的内容)。

  • 如果您的语言有一个内置的功能可以解决这个问题,则您可能无法使用它。这包括(但不限于)可以处理任意精度整数的内置类型。

  • 如果某种语言由于某种原因默认情况下使用任意精度整数,则此功能不能用于表示通常无法以64位存储的整数。

  • 输入和输出必须以10为底。不管如何将数字存储在内存中或如何对它们进行算术运算,但I / O将以10为底。

  • 您有15秒的时间来输出结果。这是为了禁止迭代减法。

  • 这里的目标是实际实现任意精度的整数。如果您出于某种原因能够遵守挑战规范,并且在没有实施挑战规范的情况下成功做到这一点,那么我想对您有好处,听起来很有效。

测试用例

  1. 在这种情况下,输入为39!还有30个!

输入值

n = 20397882081197443358640281739902897356800000000 
m = 265252859812191058636308480000000

输出量

Q = 76899763100160
R = 0
  1. n是最多50个阶乘的和的总和,再加上1。m最大是20的级联数。

输入

n = 31035053229546199656252032972759319953190362094566672920420940313
m = 1234567891011121314151617181920

输出

q = 25138393324103249083146424239449429
r = 62459510197626865203087816633
  1. n是205!+ 200!。mPeterTaylor通过撕碎我在沙箱中张贴的东西使我流了多少眼泪。

输入值

n = 271841734957981007420619769446411009306983931324177095509044302452019682761900886307931759877838550251114468516268739270368160832305944024022562873534438165159941045492295721222833276717171713647977188671055774220331117951120982666270758190446133158400369433755555593913760141099290463039666313245735358982466993720002701605636609796997120000000000000000000000000000000000000000000000000
m = 247

输出量

q = 1100573825740813795225181252819477770473619155158611722708681386445423816849801159141424129060075102231232666057768175183676764503262931271346408394876267875141461722640873365274628650676808557279259873162169126398101692109801549256156915750794061370041981513180387019893765753438422927286098434193260562682052606153857091520795991080960000000000000000000000000000000000000000000000000
r = 0;

我可能会在某个时候添加更多的测试用例。

有关

听起来很相关,但实际上并不相关


IO库是否算作外部库?
约翰逊·史蒂夫

@JohnsonSteward我不确定您的意思是什么?我默认为“是”,但您能否澄清?
利亚姆

@JohnsonSteward好吧,我想这取决于您的IOing?它是代码/代码库吗?
Ashwin Gupta'2

1
是否允许使用负数?
TheConstructor

2
@TheConstructor:根据规则:“假设n> m> 0”,所以不可以,负数是不允许的。
nimi 2016年

Answers:


4

Python 2,427字节

b=S=lambda l:sorted(l)[::-1]
A=lambda a,b,o=0:A(a^b,{n+1for n in[b&a,b-a][o]},o)if b else a
M=lambda a,*b:reduce(A,({n+m for n in a}for m in b))
def D(a,b):
 q=a-a
 while b<=S(a):n=max(a)-b[0];n-=S(M(b,n))>S(a);q|={n};a=A(a,M(b,n),1)
 return q,a
exec"a=b;b=[]\nfor d in raw_input():b=A(M(b,3,1),{i for i in range(4)if int(d)>>i&1})\n"*2
for n in D(a,S(b)):
 s=''
 while n:n,d=D(n,[3,1]);s=`sum(2**i for i in d)`+s
 print s or 0

通过STDIN读取输入,每个数字在单独的行上,并将结果打印到STDOUT。

说明

我们不是将整数表示为数字数组,而是将每个整数表示为其二进制表示形式中的一组“ on”位。即,整数Ñ被表示为一组,在的二进制表示等于1的比特的索引Ñ。例如,二进制数10、1010表示为集合{1、3}。这种表示形式使我们可以使用Python的set操作相当简洁地表达一些算术运算。

要相加两个集合,我们(递归)取它们的对称差之和,并将相继的整数集合作为它们的交集(对应于集体进位,因此最终成为空集合),此时我们得到最终的总和。)类似地,要减去两个集合,我们(递归地)取它们的对称差之差,并将后续整数的集合取为其(集合)之差(对应于集体借贷,因此最终成为空集)。这两个点的最终区别是。)这两个操作的相似性使我们可以将它们实现为单个函数(A)。

乘法(M)是简单的分布式加法:给定两个集合AB,如上所述,我们取所有集合{ A + b | b }(其中 + b是集合{ 一个 + b | 一个 })。

整数比较变成两组的字典比较,以降序排列。

为了将(D)两个集合AB相除,我们以空集合为商,并反复找到最大整数n,使得B + n小于或等于A(这只是最大值之间的差将AB的乘积(可能为负1)加上n作为商,并如上所述从A减去B + n ,直到A小于B,即直到成为余数。

当然没有免费的午餐。我们通过将十进制和十进制进行转换来支付税款。实际上,转换为十进制是大多数运行时间的过程。我们仅使用上述操作,而不是普通的算术,以“通常的方式”进行转换。


出于好奇:s=`sum(2**i for i in d)`+s转换过程中是否不使用内置的任意精度算法?
TheConstructor

1
@TheConstructor号d是一个单一的十进制数字,所以i是0和3之间,并且整个总和为0至9
埃尔

4

Java 8,485字节

如果不计算类定义,则可以再减少5个字节来命名函数,d而不是减少divide16个字节。

public class G{int l(String a){return a.length();}String s(String n,String m){while(l(n)>l(m))m=0+m;String a="";for(int c=1,i=l(n);i>0;c=c/10){c=n.charAt(--i)+c-m.charAt(i)+9;a=c%10+a;}return e(a);}String e(String a){return a.replaceAll("^0+(?=[0-9])","");}String divide(String n,String m){String q="",p=q,y;for(int b=0,i=0;b<=l(n);i--){y=n.substring(0,b);if(l(y)==l(p)&&p.compareTo(y)<=0||l(y)>l(p)){y=s(y,p);n=y+n.substring(b);q+=i;b=l(y)+1;i=10;p=m+0;}p=s(p,m);}return e(q)+","+n;}}

可以这样使用:

public static void main(String[] args) {
    G devision = new G();
    System.out.println(devision.divide("20397882081197443358640281739902897356800000000",
            "265252859812191058636308480000000"));
    System.out.println(devision.divide("31035053229546199656252032972759319953190362094566672920420940313",
            "1234567891011121314151617181920"));
    System.out.println(devision.divide(
            "271841734957981007420619769446411009306983931324177095509044302452019682761900886307931759877838550251114468516268739270368160832305944024022562873534438165159941045492295721222833276717171713647977188671055774220331117951120982666270758190446133158400369433755555593913760141099290463039666313245735358982466993720002701605636609796997120000000000000000000000000000000000000000000000000",
            "247"));
}

屈服

76899763100160,0
25138393324103249083146424239449429,62459510197626865203087816633
1100573825740813795225181252819477770473619155158611722708681386445423816849801159141424129060075102231232666057768175183676764503262931271346408394876267875141461722640873365274628650676808557279259873162169126398101692109801549256156915750794061370041981513180387019893765753438422927286098434193260562682052606153857091520795991080960000000000000000000000000000000000000000000000000,0

取消高尔夫:

public class ArbitraryPrecisionDivision {

    /**
     * Length of String
     */
    int l(String a) {
        return a.length();
    }

    /**
     * substract m of n; n >= m
     */
    String s(String n, String m) {
        while (l(n) > l(m))
            m = 0 + m;
        String a = "";
        for (int c = 1, i = l(n); i > 0; c = c / 10) {
            c = n.charAt(--i) + c - m.charAt(i) + 9;
            a = c % 10 + a;
        }
        return e(a);
    }

    /**
     * trim all leading 0s
     */
    String e(String a) {
        return a.replaceAll("^0+(?=[0-9])", "");
    }

    /**
     * divide n by m returning n/m,n%m; m may not start with a 0!
     */
    String divide(String n, String m) {
        // q stores the quotient, p stores m*i, y are the b leading digits of n
        String q = "", p = q, y;
        for (int b = 0, i = 0; b <= l(n); i--) {
            y = n.substring(0, b);
            if (l(y) == l(p) && p.compareTo(y) <= 0 || l(y) > l(p)) {
                y = s(y, p);
                n = y + n.substring(b);
                q += i;
                b = l(y) + 1;
                i = 10;
                p = m + 0;
            }
            p = s(p, m);
        }
        return e(q) + "," + n;
    }

    public static void main(String[] args) {
        ArbitraryPrecisionDivision division = new ArbitraryPrecisionDivision();
        System.out.println(division.divide("20397882081197443358640281739902897356800000000",
                "265252859812191058636308480000000"));
        System.out.println(division.divide("31035053229546199656252032972759319953190362094566672920420940313",
                "1234567891011121314151617181920"));
        System.out.println(division.divide(
                "271841734957981007420619769446411009306983931324177095509044302452019682761900886307931759877838550251114468516268739270368160832305944024022562873534438165159941045492295721222833276717171713647977188671055774220331117951120982666270758190446133158400369433755555593913760141099290463039666313245735358982466993720002701605636609796997120000000000000000000000000000000000000000000000000",
                "247"));
    }
}

我没有通过预先计算m1到9的时间并以b=0而不是开始计算数组而牺牲了一些速度b=l(m),但是这样做节省了很多字节。如果您对任意精度加法感兴趣,请参见以前的版本

我想这不是最短的解决方案,但也许它提供了一个好的开始。


如果您还为此实现加法,乘法和减法,我将为此提供500 rep赏金。:DI喜欢严格精确的想法。
Addison Crump

@VoteToClose明天会看到这个。猜猜最难的部分已经完成。
TheConstructor

1

Mathematica,251个字节

r=Reverse;f=FoldPairList;s={0}~Join~#&;
p[a_,b_]:={First@#,#[[2,1,-1,2]]}/.{Longest[0..],x__}:>{x}&@Reap@f[Sow@{Length@#-1,Last@#}&@NestWhileList[r@f[{#~Mod~10,⌊#/10⌋}&[#+Subtract@@#2]&,0,r@Thread@{#,s@b}]&,Rest@#~Join~{#2},Order[#,s@b]<=0&]&,0s@b,s@a]

说明

十进制数的算术可以轻松地通过来实现FoldPairList。例如,

times[lint_,m_]:=Reverse@FoldPairList[{#~Mod~10,⌊#/10⌋}&[m #2+#]&,0,Reverse@lint]

只是模仿手工进行乘法的过程。

times[{1,2,3,4,5},8]
(* {9,8,7,6,0} *)

测试用例

p[{1,2,3,4,5,6,7,8,9},{5,4,3,2,1}] 
(* {{2,2,7,2},{3,9,4,7,7}} *)

意味着123456789 / 54321= 2272...39477

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.