กองกำลังที่มีความแม่นยำตามอำเภอใจ


16

เราจะดำเนินการหารสำหรับจำนวนเต็มขนาดใหญ่โดยพลการ

นี่คือรหัสกอล์ฟ

งานคือการเขียนโปรแกรมหรือฟังก์ชั่นที่ใช้จำนวนเต็มความแม่นยำโดยพลการและหารกับพวกเขา

ทราบว่าหลายสิ่งหลายอย่างที่อาจทำให้เรื่องนี้ง่ายมากที่ไม่ได้รับอนุญาตโปรดให้แน่ใจว่าจะอ่านผ่านข้อมูลจำเพาะ

อินพุต

คุณจะได้รับ 2 สิ่งเป็นอินพุต:

  1. สตริงฐาน 10 nหลักเรียกว่า
  2. อีกสตริงของฐาน 10 หลักเรียกว่า m

สมมติว่าn>m>0หมายความว่าคุณจะไม่ถูกขอให้หารด้วยศูนย์

เอาท์พุต

คุณจะเอาท์พุทสองตัวเลขQและRที่m * Q + R = nและ0 <= R <m

ข้อมูลจำเพาะ

  • การส่งข้อมูลของคุณควรใช้กับจำนวนเต็มขนาดใหญ่ตามอำเภอใจ (จำกัด โดยหน่วยความจำที่มีอยู่)

  • คุณไม่สามารถใช้ไลบรารีภายนอก หากคุณต้องการไลบรารี่ภายนอกสำหรับ 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! mน้ำตาปีเตอร์เทย์เลอร์ทำให้ฉันหลั่งน้ำตาด้วยการฉีกสิ่งที่ฉันโพสต์ไว้ในกล่องทราย

อินพุต

n = 271841734957981007420619769446411009306983931324177095509044302452019682761900886307931759877838550251114468516268739270368160832305944024022562873534438165159941045492295721222833276717171713647977188671055774220331117951120982666270758190446133158400369433755555593913760141099290463039666313245735358982466993720002701605636609796997120000000000000000000000000000000000000000000000000
m = 247

เอาท์พุต

q = 1100573825740813795225181252819477770473619155158611722708681386445423816849801159141424129060075102231232666057768175183676764503262931271346408394876267875141461722640873365274628650676808557279259873162169126398101692109801549256156915750794061370041981513180387019893765753438422927286098434193260562682052606153857091520795991080960000000000000000000000000000000000000000000000000
r = 0;

ฉันอาจจะเพิ่มกรณีทดสอบเพิ่มเติมในบางจุด

ที่เกี่ยวข้อง

เสียงเกี่ยวข้อง แต่จริงๆแล้วไม่ใช่


ห้องสมุด IO นับเป็นห้องสมุดภายนอกหรือไม่?
Johnson Steward

@JohnsonSteward ฉันไม่แน่ใจว่าคุณหมายถึงอะไร? ฉันจะตั้งค่าเริ่มต้นเป็น "ใช่" แต่คุณช่วยอธิบายได้ไหม
เลียม

@Johnson เริ่มต้นดีฉันคิดว่ามันขึ้นอยู่กับสิ่งที่คุณกำลัง IOing มันเป็นรหัส / ไลบรารีของรหัสหรือไม่?
Ashwin Gupta

1
อนุญาตให้ใช้จำนวนลบได้หรือไม่
TheConstructor

2
@TheConstructor: จากกฎ: "สมมติว่า n> m> 0" ดังนั้นไม่อนุญาตให้ใช้จำนวนลบ
nimi

คำตอบ:


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

คำอธิบาย

แทนที่จะแสดงจำนวนเต็มเป็นอาร์เรย์ของตัวเลขเราแทนแต่ละจำนวนเต็มเป็นชุดของบิต "กับ" ในการแทนเลขฐานสอง นั่นคือจำนวนเต็มnจะแสดงเป็นชุดของดัชนีของบิตที่เท่ากับ 1 ในฐานเป็นตัวแทนของn ตัวอย่างเช่นหมายเลข 10, 1010 ในไบนารีจะแสดงเป็นชุด {1, 3} การเป็นตัวแทนนี้ช่วยให้เราสามารถแสดงการดำเนินการทางคณิตศาสตร์บางส่วนได้ค่อนข้างรัดกุมโดยใช้การดำเนินการของ Python

ในการเพิ่มสองชุดเรา (เรียกซ้ำ) ใช้ผลรวมของความแตกต่างสมมาตรและชุดของจำนวนเต็มที่ประสบความสำเร็จในการแยกของพวกเขา (ซึ่งสอดคล้องกับการรวมกลุ่มและในที่สุดกลายเป็นเซตว่าง ณ จุดที่เรามีผลรวมสุดท้าย .) ในทำนองเดียวกันเพื่อลบสองชุดเรา (เรียกซ้ำ) ใช้ความแตกต่างของความแตกต่างสมมาตรของพวกเขาและชุดของจำนวนเต็มที่ประสบความสำเร็จต่อความแตกต่าง (ชุด) ของพวกเขา (ซึ่งสอดคล้องกับกลุ่มกู้ยืมและในที่สุดก็กลายเป็นชุดว่างเปล่า จุดที่เรามีความแตกต่างสุดท้าย) ความคล้ายคลึงกันของการดำเนินการทั้งสองนี้ช่วยให้เราสามารถใช้พวกเขาเป็นฟังก์ชั่นเดียว ( A)

การคูณ ( M) มีการแจกแจงแบบง่ายๆ: เมื่อได้รับสองชุดAและBเราจะหาผลรวมตามที่อธิบายไว้ข้างต้นของทุกชุด { A + b | bB } (โดยที่A + bคือชุด { a + b | aA })

การเปรียบเทียบจำนวนเต็มจะกลายเป็นการเปรียบเทียบพจนานุกรมทั้งสองชุดเรียงตามลำดับจากมากไปน้อย

ในการหาร ( D) สองชุดAและBเราเริ่มต้นด้วยชุดที่ว่างเปล่าเป็นผลหารและหาจำนวนเต็มที่ใหญ่ที่สุดnซ้ำ ๆเช่นB + n น้อยกว่าหรือเท่ากับA (ซึ่งก็คือความแตกต่างระหว่าง maxima ของAและBอาจเป็นลบ -1) เพิ่มnเป็นองค์ประกอบในความฉลาดและลบB + n จากAตามที่อธิบายข้างต้นจนกระทั่งAกลายเป็นน้อยกว่าBคือจนกว่ามันจะกลายเป็นส่วนที่เหลือ

ไม่มีอาหารกลางวันฟรีแน่นอน เราจ่ายภาษีโดยต้องแปลงจาก - และเป็นทศนิยม ในความเป็นจริงการแปลงเป็นทศนิยมคือสิ่งที่ใช้เวลาส่วนใหญ่ เราทำการแปลง "วิธีปกติ" เพียงใช้การดำเนินการด้านบนแทนการคำนวณทางคณิตศาสตร์ธรรมดา


เพิ่งออกมาจากความอยากรู้: ไม่s=`sum(2**i for i in d)`+sใช้เลขคณิตความแม่นยำในตัวระหว่างการแปลงหรือไม่
TheConstructor

1
@ TheConstructor No. dเป็นเลขทศนิยมหลักเดียวดังนั้นจึงiอยู่ระหว่าง 0 ถึง 3 และผลรวมทั้งหมดอยู่ระหว่าง 0 ถึง 9
Ell

4

Java 8, 485 ไบต์

สามารถลดขนาดได้อีก 5 ไบต์การตั้งชื่อฟังก์ชั่นdแทนdivideหรืออีก 16 ไบต์ถ้าไม่นับการกำหนดคลาส

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

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

ฉันเสียสละความเร็วเพียงเล็กน้อยโดยไม่ทำการคำนวณอาร์เรย์ล่วงหน้าด้วยmเวลา 1 ถึง 9 และเริ่มต้นด้วยb=0แทนที่จะเป็นb=l(m)แต่ช่วยประหยัดจำนวนไบต์ได้ หากคุณมีความสนใจในนอกจากความแม่นยำโดยพลการดูรุ่นก่อนหน้า

ฉันเดาว่านี่จะไม่ใช่วิธีแก้ปัญหาที่สั้นที่สุด แต่อาจจะเป็นการเริ่มต้นที่ดี


หากคุณใช้การบวกการคูณและการลบสำหรับสิ่งนี้เช่นกันฉันจะสร้างเงินรางวัล 500 ตัวแทนให้กับสิ่งนี้ : 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วิธี

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.