División de enteros de precisión arbitraria


16

Implementaremos división para enteros arbitrariamente grandes.

Este es el .

La tarea es escribir un programa o función que implemente números enteros de precisión arbitraria y División en ellos.

Tenga en cuenta que muchas cosas que podrían hacer que esto sea muy fácil no están permitidas, asegúrese de leer las especificaciones .

Entrada

Se le darán 2 cosas como entrada:

  1. una cadena de base 10 dígitos, llámalo n.
  2. otra cadena de 10 dígitos base, llámalo m

Suponga quen>m>0 significa que nunca se le pedirá que divida por cero .

Salida

Se quiere salida dos números, Qy Rdonde m * Q + R = n y 0 <= R <m

Especificaciones

  • Su envío debería funcionar para enteros arbitrariamente grandes (limitado por la memoria disponible).

  • No puede usar bibliotecas externas. Si necesita una biblioteca externa para E / S, puede tratarla como una función incorporada. (mirando cosas como iostream, etc.).

  • Si su idioma tiene una función incorporada que lo trivializa, no puede usarlo. Esto incluye (pero no se limita a) los tipos integrados que pueden manejar enteros de precisión arbitrarios.

  • Si, por algún motivo, un idioma usa enteros de precisión arbitraria de forma predeterminada, esta funcionalidad no se puede usar para representar enteros que normalmente no podrían almacenarse en 64 bits.

  • La entrada y la salida DEBEN estar en la base 10 . No importa cómo almacene los números en la memoria o cómo realice la aritmética en ellos, pero la E / S será la base 10.

  • Tienes 15 segundos para generar un resultado. Esto es para prohibir la resta iterada.

  • El objetivo aquí es implementar realmente enteros de precisión arbitrarios. Si por alguna razón puedes cumplir con las especificaciones del desafío y hacerlo con éxito sin implementarlas, bueno, supongo que es bueno para ti, parece válido.

Casos de prueba

  1. En este caso, las entradas son 39! y 30!

Entrada

n = 20397882081197443358640281739902897356800000000 
m = 265252859812191058636308480000000

Salida

Q = 76899763100160
R = 0
  1. nes la suma de todos los factoriales hasta 50, más 1. mson números concatenados hasta 20.

entrada

n = 31035053229546199656252032972759319953190362094566672920420940313
m = 1234567891011121314151617181920

salida

q = 25138393324103249083146424239449429
r = 62459510197626865203087816633
  1. nes 205! + 200 !. mes cuántas lágrimas PeterTaylor me ha hecho derramar al destrozar cosas que publico en la caja de arena.

Entrada

n = 271841734957981007420619769446411009306983931324177095509044302452019682761900886307931759877838550251114468516268739270368160832305944024022562873534438165159941045492295721222833276717171713647977188671055774220331117951120982666270758190446133158400369433755555593913760141099290463039666313245735358982466993720002701605636609796997120000000000000000000000000000000000000000000000000
m = 247

Salida

q = 1100573825740813795225181252819477770473619155158611722708681386445423816849801159141424129060075102231232666057768175183676764503262931271346408394876267875141461722640873365274628650676808557279259873162169126398101692109801549256156915750794061370041981513180387019893765753438422927286098434193260562682052606153857091520795991080960000000000000000000000000000000000000000000000000
r = 0;

Probablemente agregaré más casos de prueba en algún momento.

Relacionado

Suena relacionado, pero realmente no lo es


¿Las bibliotecas IO cuentan como bibliotecas externas?
Johnson Steward

@JohnsonSteward ¿No estoy seguro de qué quieres decir con eso? Por defecto sería "sí", pero ¿podría aclararlo?
Liam

@JohnsonSteward bueno, supongo que depende de lo que estás haciendo. ¿Es código / una biblioteca de código?
Ashwin Gupta

1
¿Se permiten números negativos?
TheConstructor

2
@TheConstructor: de las reglas: "suponga que n> m> 0", por lo que no, no se permiten números negativos.
nimi

Respuestas:


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

Lee la entrada a través de STDIN, cada número en una línea separada e imprime el resultado en STDOUT.

Explicación

En lugar de representar enteros como matrices de dígitos, representamos cada entero como el conjunto de bits "on" en su representación binaria. Es decir, un número entero n se representa como el conjunto de índices de los bits que equivalen a 1 en la representación binaria de n . Por ejemplo, el número 10, 1010 en binario, se representa como el conjunto {1, 3}. Esta representación nos permite expresar algunas de las operaciones aritméticas de manera bastante sucinta, utilizando las operaciones de conjuntos de Python.

Para agregar dos conjuntos, nosotros (recursivamente) tomamos la suma de su diferencia simétrica y el conjunto de enteros sucesivos en su intersección (que corresponde al transporte colectivo y, por lo tanto, finalmente se convierte en el conjunto vacío, en cuyo punto tenemos la suma final .) De manera similar, para restar dos conjuntos, tomamos (recursivamente) la diferencia de su diferencia simétrica, y el conjunto de enteros sucesivos a su diferencia (conjunto) (que corresponde al préstamo colectivo, y por lo tanto eventualmente se convierte en el conjunto vacío, en en qué punto tenemos la diferencia final.) La similitud de estas dos operaciones nos permite implementarlas como una sola función ( A).

La multiplicación ( M) es una suma simplemente distribuida: dados dos conjuntos A y B , tomamos la suma, como se describió anteriormente, de todos los conjuntos { A + b | bB } (donde A + b es el conjunto { a + b | aA }).

La comparación de enteros se convierte en una comparación lexicográfica de los dos conjuntos, ordenados en orden descendente.

Para dividir ( D) dos conjuntos, A y B , comenzamos con el conjunto vacío como cociente, y repetidamente encontramos el número entero más grande n , de modo que B + n sea menor o igual que A (que es simplemente la diferencia entre los máximos de A y B , posiblemente menos-1), sume n como un elemento al cociente y reste B + n de A , como se describió anteriormente, hasta que A sea ​​menor que B , es decir, hasta que se convierta en el resto.

No hay almuerzo gratis, por supuesto. Pagamos el impuesto al tener que convertir de- y a-, decimal. De hecho, la conversión a decimal es lo que toma la mayor parte del tiempo de ejecución. Hacemos la conversión "de la manera habitual", solo usando las operaciones anteriores, en lugar de la aritmética ordinaria.


Solo por curiosidad: ¿no s=`sum(2**i for i in d)`+sutiliza la aritmética de precisión arbitraria incorporada durante la conversión?
TheConstructor

1
@TheConstructor No. des un solo dígito decimal, por lo que iestá entre 0 y 3, y la suma total está entre 0 y 9.
Ell

4

Java 8, 485 bytes

Podría reducir otros 5 bytes nombrando la función en dlugar de divideotros 16 bytes si no cuenta la definición de clase.

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

Se puede usar así:

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

flexible

76899763100160,0
25138393324103249083146424239449429,62459510197626865203087816633
1100573825740813795225181252819477770473619155158611722708681386445423816849801159141424129060075102231232666057768175183676764503262931271346408394876267875141461722640873365274628650676808557279259873162169126398101692109801549256156915750794061370041981513180387019893765753438422927286098434193260562682052606153857091520795991080960000000000000000000000000000000000000000000000000,0

Sin golf:

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

Sacrifiqué un poco de velocidad al no calcular previamente una matriz con mtiempos del 1 al 9 y comenzar con en b=0lugar deb=l(m) , pero ahorré muchos bytes al hacerlo. Si está interesado en la adición de precisión arbitraria, consulte una versión anterior .

Supongo que esta no será la solución más corta, pero tal vez sea un buen comienzo.


Si implementas además, multiplicación y resta para esto, haré una recompensa de 500 repeticiones por esto. : Me encanta la idea de precisión Stringy.
Addison Crump

@VoteToClose se encargará de esto mañana. Supongo que la parte más difícil está hecha.
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]

Explicación

La aritmética en números decimales se puede implementar fácilmente mediante FoldPairList. Por ejemplo,

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

simplemente imita el proceso de hacer multiplicaciones a mano.

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

Caso de prueba

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

significa 123456789 / 54321= 2272...39477.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.