Divisi Integer Presisi Sewenang-wenang


16

Kami akan menerapkan divisi untuk bilangan bulat besar yang sewenang-wenang.

Ini adalah .

Tugasnya adalah untuk menulis program atau fungsi yang mengimplementasikan bilangan bulat presisi presisi dan Divisi pada mereka.

Perhatikan bahwa banyak hal yang membuat ini sangat mudah tidak diizinkan, pastikan untuk membaca spesifikasi .

Memasukkan

Anda akan diberikan 2 hal sebagai masukan:

  1. string basis 10 digit, sebut saja n.
  2. string lain dari basis 10 digit, sebut saja m

Asumsikan itun>m>0 berarti bahwa Anda tidak akan pernah diminta untuk membagi dengan nol .

Keluaran

Anda akan menampilkan dua angka, Qdan di Rmana m * Q + R = n dan 0 <= R <m

Spesifikasi

  • Kiriman Anda harus berfungsi untuk bilangan bulat besar yang sewenang-wenang (dibatasi oleh memori yang tersedia).

  • Anda tidak boleh menggunakan perpustakaan eksternal. Jika Anda membutuhkan perpustakaan eksternal untuk i / o, Anda dapat memperlakukannya sebagai built-in. (melihat hal-hal seperti iostream, dll).

  • Jika bahasa Anda memiliki built-in yang meremehkan ini, Anda mungkin tidak menggunakannya. Ini termasuk (tetapi mungkin tidak terbatas pada) tipe bawaan yang dapat menangani bilangan bulat presisi sewenang-wenang.

  • Jika suatu bahasa karena suatu alasan menggunakan bilangan bulat presisi arbitrer secara default, fungsi ini tidak dapat digunakan untuk mewakili bilangan bulat yang tidak dapat biasanya disimpan dalam 64 bit.

  • Input dan output HARUS berada di basis 10 . Tidak masalah bagaimana Anda menyimpan angka dalam memori atau bagaimana Anda melakukan aritmatika pada mereka, tetapi i / o akan menjadi basis 10.

  • Anda memiliki 15 Detik untuk menampilkan hasil. Ini untuk mencegah pengurangan yang diulang.

  • Tujuannya di sini adalah untuk benar-benar mengimplementasikan bilangan bulat presisi sewenang-wenang. Jika karena alasan tertentu Anda dapat mematuhi spesifikasi tantangan dan berhasil melakukan ini tanpa menerapkannya, baik saya kira baik untuk Anda, kedengarannya valid.

Uji Kasus

  1. Dalam hal ini, inputnya adalah 39! dan 30!

Memasukkan

n = 20397882081197443358640281739902897356800000000 
m = 265252859812191058636308480000000

Keluaran

Q = 76899763100160
R = 0
  1. nadalah jumlah semua faktorial hingga 50, ditambah 1. madalah angka gabungan hingga 20.

memasukkan

n = 31035053229546199656252032972759319953190362094566672920420940313
m = 1234567891011121314151617181920

keluaran

q = 25138393324103249083146424239449429
r = 62459510197626865203087816633
  1. nadalah 205! + 200 !. madalah berapa banyak air mata yang PeterTaylor buat untuk saya tumpahkan dengan merobek-robek hal-hal yang saya poskan di kotak pasir.

Memasukkan

n = 271841734957981007420619769446411009306983931324177095509044302452019682761900886307931759877838550251114468516268739270368160832305944024022562873534438165159941045492295721222833276717171713647977188671055774220331117951120982666270758190446133158400369433755555593913760141099290463039666313245735358982466993720002701605636609796997120000000000000000000000000000000000000000000000000
m = 247

Keluaran

q = 1100573825740813795225181252819477770473619155158611722708681386445423816849801159141424129060075102231232666057768175183676764503262931271346408394876267875141461722640873365274628650676808557279259873162169126398101692109801549256156915750794061370041981513180387019893765753438422927286098434193260562682052606153857091520795991080960000000000000000000000000000000000000000000000000
r = 0;

Saya mungkin akan menambahkan lebih banyak test case di beberapa titik.

Terkait

Kedengarannya terkait, tetapi sebenarnya tidak


Apakah perpustakaan IO dihitung sebagai perpustakaan eksternal?
Johnson Steward

@ JohnsonSteward Saya tidak yakin apa yang Anda maksud dengan itu? Saya akan default ke "ya", tetapi bisakah Anda mengklarifikasi?
Liam

@ JohnsonSteward baik saya kira itu tergantung pada apa yang Anda IOing? Apakah itu kode / pustaka kode?
Ashwin Gupta

1
Apakah angka negatif diperbolehkan?
TheConstructor

2
@TheConstructor: from the rules: "asumsikan bahwa n> m> 0", jadi tidak, angka negatif tidak diperbolehkan.
nimi

Jawaban:


4

Python 2, 427 byte

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

Membaca input melalui STDIN, masing-masing nomor pada baris yang terpisah, dan mencetak hasilnya ke STDOUT.

Penjelasan

Alih-alih mewakili bilangan bulat sebagai array angka, kami mewakili setiap bilangan bulat sebagai himpunan bit "on" dalam representasi binernya. Artinya, bilangan bulat n direpresentasikan sebagai kumpulan indeks bit yang sama dengan 1 dalam representasi biner n . Sebagai contoh, angka 10, 1010 dalam biner, direpresentasikan sebagai himpunan {1, 3}. Representasi ini memungkinkan kita untuk mengekspresikan beberapa operasi aritmatika dengan lebih ringkas, menggunakan operasi himpunan Python.

Untuk menambahkan dua set, kita (secara rekursif) mengambil jumlah dari perbedaan simetris mereka, dan set integer yang berhasil ke persimpangan mereka (yang sesuai dengan carry kolektif, dan karenanya akhirnya menjadi set kosong, di mana kita memiliki jumlah akhir .) Demikian pula, untuk mengurangi dua set, kami (secara rekursif) mengambil perbedaan dari perbedaan simetris mereka, dan himpunan bilangan yang berhasil untuk perbedaan (himpunan) mereka (yang sesuai dengan pinjaman kolektif, dan karenanya menjadi himpunan kosong, pada titik mana kita memiliki perbedaan final.) Kesamaan dari dua operasi ini memungkinkan kita untuk mengimplementasikannya sebagai fungsi tunggal (A ).

Perkalian ( M) adalah tambahan yang didistribusikan secara sederhana: diberikan dua set A dan B , kita mengambil jumlah, seperti yang dijelaskan di atas, dari semua set { A + b | bB } (di mana A + b adalah himpunan { a + b | aA }).

Perbandingan integer menjadi perbandingan leksikografis dari dua set, diurutkan dalam urutan menurun.

Untuk membagi ( D) dua set, A dan B , kita mulai dengan set kosong sebagai hasil bagi, dan berulang kali menemukan bilangan bulat n terbesar , sehingga B + n kurang dari atau sama dengan A (yang hanya merupakan perbedaan antara maksimum dari A dan B , mungkin minus-1), tambahkan n sebagai elemen bagi hasil bagi, dan kurangi B + n dari A , seperti dijelaskan di atas, sampai A menjadi kurang dari B , yaitu, sampai menjadi sisanya.

Tidak ada makan siang gratis, tentu saja. Kami membayar pajak dengan harus mengonversi dari-, dan ke-, desimal. Faktanya, konversi ke desimal adalah yang paling memakan waktu berjalan. Kami melakukan konversi "dengan cara biasa", hanya menggunakan operasi di atas, bukan aritmatika biasa.


Hanya ingin tahu: tidak s=`sum(2**i for i in d)`+smenggunakan aritmatika presisi arbitrer bawaan selama konversi?
TheConstructor

1
@TheConstructor No. dadalah angka desimal tunggal, demikian ijuga antara 0 dan 3, dan seluruh jumlah adalah antara 0 dan 9.
Ell

4

Java 8, 485 byte

Bisa mengurangi 5 byte lain penamaan fungsi, dbukandivide atau 16 byte lain jika tidak menghitung definisi kelas.

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

Dapat digunakan seperti ini:

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

menghasilkan

76899763100160,0
25138393324103249083146424239449429,62459510197626865203087816633
1100573825740813795225181252819477770473619155158611722708681386445423816849801159141424129060075102231232666057768175183676764503262931271346408394876267875141461722640873365274628650676808557279259873162169126398101692109801549256156915750794061370041981513180387019893765753438422927286098434193260562682052606153857091520795991080960000000000000000000000000000000000000000000000000,0

Tidak Terkumpul:

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

Saya mengorbankan sedikit kecepatan dengan tidak menghitung ulang array dengan mwaktu 1 hingga 9 dan mulai dengan b=0alih - alihb=l(m) , tetapi menghemat banyak byte dengan melakukannya. Jika Anda tertarik pada penambahan presisi sewenang-wenang, lihat versi sebelumnya .

Saya kira ini bukan solusi tersingkat, tapi mungkin ini memberikan awal yang baik.


Jika Anda menerapkan penambahan, perkalian, dan pengurangan untuk ini juga, saya akan membuat hadiah 500 rep untuk ini. : D Saya suka ide ketelitian Stringy.
Addison Crump

@VoteToClose akan melihat ini besok. Kira bagian tersulit dilakukan.
TheConstructor

1

Mathematica, 251 byte

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]

Penjelasan

Aritmatika pada angka desimal dapat dengan mudah diterapkan oleh FoldPairList. Sebagai contoh,

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

hanya meniru proses melakukan perkalian dengan tangan.

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

Kasus cobaan

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

berarti 123456789 / 54321= 2272...39477.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.