Divisão Inteira de Precisão Arbitrária


16

Implementaremos divisão para números inteiros arbitrariamente grandes.

Isso é .

A tarefa é escrever um programa ou função que implemente números inteiros de precisão arbitrários e divisão neles.

Observe que muitas coisas que podem facilitar muito isso não são permitidas; leia as especificações .

Entrada

Você receberá duas coisas como entrada:

  1. uma sequência de 10 dígitos base, chame-a n.
  2. outra sequência de 10 dígitos base, chame-a m

Suponha quen>m>0 significa que você nunca será solicitado a dividir por zero .

Resultado

Está output dois números, Qe Ronde m * Q + R = n e 0 <= R <m

Especificações

  • Seu envio deve funcionar para números inteiros arbitrariamente grandes (limitados pela memória disponível).

  • Você não pode usar bibliotecas externas. Se você precisar de uma biblioteca externa para E / S, poderá tratá-la como um built-in. (olhando para coisas como iostream, etc).

  • Se seu idioma possui um built-in que trivializa isso, você não pode usá-lo. Isso inclui (mas não pode ser limitado a) tipos internos que podem manipular números inteiros de precisão arbitrários.

  • Se, por algum motivo, um idioma usar números inteiros de precisão arbitrários por padrão, essa funcionalidade não poderá ser usada para representar números inteiros que normalmente não poderiam ser armazenados em 64 bits.

  • Entrada e saída DEVE estar na base 10 . Não importa como você armazena os números na memória ou como executa aritmética neles, mas a E / S será a base 10.

  • Você tem 15 segundos para produzir um resultado. Isso é para proibir a subtração iterada.

  • O objetivo aqui é realmente implementar números inteiros de precisão arbitrários. Se, por algum motivo, você conseguir aderir às especificações do desafio e fazê-lo com êxito sem implementá-las, acho que é bom para você, parece válido.

Casos de teste

  1. Nesse caso, as entradas são 39! e 30!

Entrada

n = 20397882081197443358640281739902897356800000000 
m = 265252859812191058636308480000000

Resultado

Q = 76899763100160
R = 0
  1. né a soma de todos os fatoriais até 50, mais 1. msão números concatenados até 20.

entrada

n = 31035053229546199656252032972759319953190362094566672920420940313
m = 1234567891011121314151617181920

resultado

q = 25138393324103249083146424239449429
r = 62459510197626865203087816633
  1. né 205! + 200 !. mé quantas lágrimas PeterTaylor me fez derramar rasgando as coisas que coloco na caixa de areia.

Entrada

n = 271841734957981007420619769446411009306983931324177095509044302452019682761900886307931759877838550251114468516268739270368160832305944024022562873534438165159941045492295721222833276717171713647977188671055774220331117951120982666270758190446133158400369433755555593913760141099290463039666313245735358982466993720002701605636609796997120000000000000000000000000000000000000000000000000
m = 247

Resultado

q = 1100573825740813795225181252819477770473619155158611722708681386445423816849801159141424129060075102231232666057768175183676764503262931271346408394876267875141461722640873365274628650676808557279259873162169126398101692109801549256156915750794061370041981513180387019893765753438422927286098434193260562682052606153857091520795991080960000000000000000000000000000000000000000000000000
r = 0;

Provavelmente adicionarei mais casos de teste em algum momento.

Relacionado

Parece relacionado, mas realmente não é


As bibliotecas de E / S contam como bibliotecas externas?
Johnson Steward

@JohnsonSteward Não tenho certeza do que você quer dizer com isso? O padrão seria "yes", mas você poderia esclarecer?
Liam

@JohnsonSteward bem, suponho que depende do que você está fazendo? É código / uma biblioteca de códigos?
Ashwin Gupta

1
Números negativos são permitidos?
TheConstructor

2
@ TheConstructor: das regras: "assuma que n> m> 0", então não, números negativos não são permitidos.
nimi

Respostas:


4

Python 2, 427 bytes

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

Lê a entrada através de STDIN, cada número em uma linha separada e imprime o resultado em STDOUT.

Explicação

Em vez de representar números inteiros como matrizes de dígitos, representamos cada número inteiro como o conjunto de bits "on" em sua representação binária. Ou seja, um número inteiro n é representado como o conjunto de índices dos bits que são iguais a 1 na representação binária de n . Por exemplo, o número 10, 1010 em binário, é representado como o conjunto {1, 3}. Essa representação nos permite expressar algumas das operações aritméticas de maneira sucinta, usando as operações de conjunto do Python.

Para adicionar dois conjuntos, tomamos (recursivamente) a soma de sua diferença simétrica e o conjunto de números inteiros sucessivos para sua interseção (que corresponde ao transporte coletivo e, portanto, eventualmente se torna o conjunto vazio, nesse ponto temos a soma final .) Da mesma forma, para subtrair dois conjuntos, tomamos (recursivamente) a diferença de sua diferença simétrica e o conjunto de números inteiros sucessivos para sua diferença (de conjunto) (que corresponde ao empréstimo coletivo e, portanto, eventualmente se torna o conjunto vazio, em Nesse ponto, temos a diferença final.) A semelhança dessas duas operações nos permite implementá-las como uma única função ( A).

Multiplicação ( M) é simplesmente adição distribuída: dados dois conjuntos A e B , obtemos a soma, como descrito acima, de todos os conjuntos { A + b | bB } (onde A + b é o conjunto { a + b | aA }).

A comparação inteira se torna uma comparação lexicográfica dos dois conjuntos, classificados em ordem decrescente.

Para dividir ( D) dois conjuntos, A e B , começamos com o conjunto vazio como quociente e encontramos repetidamente o maior número inteiro n , de modo que B + n seja menor ou igual a A (que é simplesmente a diferença entre os máximos de A e B , possivelmente menos -1), adicione n como elemento ao quociente e subtraia B + n de A , como descrito acima, até que A se torne menor que B , ou seja, até que se torne o restante.

Não há almoço grátis, é claro. Pagamos o imposto tendo que converter de e para decimal. De fato, a conversão para decimal é o que leva a maior parte do tempo de execução. Fazemos a conversão "da maneira usual", apenas usando as operações acima, em vez da aritmética comum.


Apenas por curiosidade: não s=`sum(2**i for i in d)`+sutiliza aritmética de precisão arbitrária incorporada durante a conversão?
TheConstructor

1
@O número do construtor dé um único dígito decimal, portanto, iestá entre 0 e 3, e a soma total está entre 0 e 9. #
9292 Ell Ell

4

Java 8, 485 bytes

Pode reduzir em mais 5 bytes nomeando a função em dvez de divideou em outros 16 bytes se não contar a definição de classe.

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;}}

Pode ser usado assim:

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"));
}

produzindo

76899763100160,0
25138393324103249083146424239449429,62459510197626865203087816633
1100573825740813795225181252819477770473619155158611722708681386445423816849801159141424129060075102231232666057768175183676764503262931271346408394876267875141461722640873365274628650676808557279259873162169126398101692109801549256156915750794061370041981513180387019893765753438422927286098434193260562682052606153857091520795991080960000000000000000000000000000000000000000000000000,0

Ungolfed:

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"));
    }
}

Eu sacrifiquei um pouco de velocidade, não pré-calculando uma matriz com os mtempos de 1 a 9 e iniciando em b=0vez de b=l(m), mas economizei muitos bytes ao fazê-lo. Se você estiver interessado em adição de precisão arbitrária, consulte uma versão anterior .

Acho que essa não será a solução mais curta, mas talvez dê um bom começo.


Se você implementar adição, multiplicação e subtração para isso também, farei uma recompensa de 500 representantes. : Eu adoro a idéia de precisão Stringy.
Addison Crump

A @VoteToClose cuidará disso amanhã. Acho que a parte mais difícil está feita.
TheConstructor

1

Mathematica, 251 bytes

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]

Explicação

Aritmética em números decimais pode ser facilmente implementada por FoldPairList. Por exemplo,

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

apenas imita o processo de fazer multiplicações manualmente.

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

Caso de teste

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

meios 123456789 / 54321= 2272...39477.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.